svn rev #24259: branches/plugins2/ doc/ src/ src/config-files/ src/include/ src/include/krb5/ ...
ghudson@MIT.EDU
ghudson at MIT.EDU
Thu Aug 26 19:19:41 EDT 2010
http://src.mit.edu/fisheye/changelog/krb5/?cs=24259
Commit By: ghudson
Log Message:
Merge trunk changes from r24202 to r24258 to plugins2 branch.
Changed Files:
U branches/plugins2/doc/krb5conf.texinfo
U branches/plugins2/src/Makefile.in
U branches/plugins2/src/config-files/krb5.conf.M
U branches/plugins2/src/include/Makefile.in
U branches/plugins2/src/include/k5-int.h
U branches/plugins2/src/include/krb5/krb5.hin
U branches/plugins2/src/kdc/do_as_req.c
D branches/plugins2/src/lib/gssapi/generic/util_canonhost.c
D branches/plugins2/src/lib/gssapi/generic/util_localhost.c
U branches/plugins2/src/lib/gssapi/krb5/acquire_cred.c
U branches/plugins2/src/lib/gssapi/krb5/krb5_gss_glue.c
U branches/plugins2/src/lib/kadm5/kadm_rpc_xdr.c
U branches/plugins2/src/lib/krb5/error_tables/Makefile.in
A branches/plugins2/src/lib/krb5/error_tables/k5e1_err.et
U branches/plugins2/src/lib/krb5/krb/Makefile.in
U branches/plugins2/src/lib/krb5/krb/gic_opt.c
U branches/plugins2/src/lib/krb5/krb/gic_pwd.c
U branches/plugins2/src/lib/krb5/krb/rd_req_dec.c
A branches/plugins2/src/lib/krb5/krb/t_expire_warn.c
A branches/plugins2/src/lib/krb5/krb/t_expire_warn.py
U branches/plugins2/src/lib/krb5/libkrb5.exports
U branches/plugins2/src/lib/rpc/xdr.c
U branches/plugins2/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
U branches/plugins2/src/util/k5test.py
_U branches/plugins2/src/util/profile/
U branches/plugins2/src/util/profile/prof_err.et
U branches/plugins2/src/util/profile/prof_init.c
U branches/plugins2/src/util/profile/prof_parse.c
U branches/plugins2/src/util/profile/prof_test1
Modified: branches/plugins2/doc/krb5conf.texinfo
===================================================================
--- branches/plugins2/doc/krb5conf.texinfo 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/doc/krb5conf.texinfo 2010-08-26 23:19:40 UTC (rev 24259)
@@ -40,6 +40,21 @@
then the second value of foo (baz) would never be read.
+The @code{krb5.conf} file can include other files using either of the
+following directives at the beginning of a line:
+
+ at smallexample
+include @var{FILENAME}
+includedir @var{DIRNAME}
+ at end smallexample
+
+ at var{FILENAME} or @var{DIRNAME} should be an absolute path. The named
+file or directory must exist and be readable. Including a directory
+includes all files within the directory whose names consist solely of
+alphanumeric characters, dashes, or underscores. Included profile files
+are syntactically independent of their parents, so each included file
+must begin with a section header.
+
The @code{krb5.conf} file may contain any or all of the following
sections:
Modified: branches/plugins2/src/Makefile.in
===================================================================
--- branches/plugins2/src/Makefile.in 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/Makefile.in 2010-08-26 23:19:40 UTC (rev 24259)
@@ -445,6 +445,7 @@
$(INC)asn1_err.h $(ET)asn1_err.c \
$(INC)kdb5_err.h $(ET)kdb5_err.c \
$(INC)krb5_err.h $(ET)krb5_err.c \
+ $(INC)k5e1_err.h $(ET)k5e1_err.c \
$(INC)kv5m_err.h $(ET)kv5m_err.c \
$(INC)krb524_err.h $(ET)krb524_err.c \
$(PR)prof_err.h $(PR)prof_err.c \
@@ -501,6 +502,8 @@
$(AWK) -f $(AH) outfile=$@ $(ET)kdb5_err.et
$(INC)krb5_err.h: $(AH) $(ET)krb5_err.et
$(AWK) -f $(AH) outfile=$@ $(ET)krb5_err.et
+$(INC)k5e1_err.h: $(AH) $(ET)k5e1_err.et
+ $(AWK) -f $(AH) outfile=$@ $(ET)k5e1_err.et
$(INC)kv5m_err.h: $(AH) $(ET)kv5m_err.et
$(AWK) -f $(AH) outfile=$@ $(ET)kv5m_err.et
$(INC)krb524_err.h: $(AH) $(ET)krb524_err.et
@@ -524,6 +527,8 @@
$(AWK) -f $(AC) outfile=$@ $(ET)kdb5_err.et
$(ET)krb5_err.c: $(AC) $(ET)krb5_err.et
$(AWK) -f $(AC) outfile=$@ $(ET)krb5_err.et
+$(ET)k5e1_err.c: $(AC) $(ET)k5e1_err.et
+ $(AWK) -f $(AC) outfile=$@ $(ET)k5e1_err.et
$(ET)kv5m_err.c: $(AC) $(ET)kv5m_err.et
$(AWK) -f $(AC) outfile=$@ $(ET)kv5m_err.et
$(ET)krb524_err.c: $(AC) $(ET)krb524_err.et
@@ -541,8 +546,8 @@
$(CE)test2.c: $(AC) $(CE)test2.et
$(AWK) -f $(AC) outfile=$@ $(CE)test2.et
-KRBHDEP = $(INC)krb5\krb5.hin $(INC)krb5_err.h $(INC)kdb5_err.h \
- $(INC)kv5m_err.h $(INC)krb524_err.h $(INC)asn1_err.h
+KRBHDEP = $(INC)krb5\krb5.hin $(INC)krb5_err.h $(INC)k5e1_err.h \
+ $(INC)kdb5_err.h $(INC)kv5m_err.h $(INC)krb524_err.h $(INC)asn1_err.h
$(INC)krb5\krb5.h: $(KRBHDEP)
rm -f $@
Modified: branches/plugins2/src/config-files/krb5.conf.M
===================================================================
--- branches/plugins2/src/config-files/krb5.conf.M 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/config-files/krb5.conf.M 2010-08-26 23:19:40 UTC (rev 24259)
@@ -60,6 +60,17 @@
.sp
.PP
+.I krb5.conf
+can include other files using the directives "include FILENAME" or
+"includedir DIRNAME", which must occur at the beginning of a line.
+FILENAME or DIRNAME should be an absolute path. The named file or
+directory must exist and be readable. Including a directory includes
+all files within the directory whose names consist solely of
+alphanumeric characters, dashes, or underscores. Included profile
+files are syntactically independent of their parents, so each included
+file must begin with a section header.
+
+.PP
The following sections are currently used in the
.I krb5.conf
file:
Modified: branches/plugins2/src/include/Makefile.in
===================================================================
--- branches/plugins2/src/include/Makefile.in 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/include/Makefile.in 2010-08-26 23:19:40 UTC (rev 24259)
@@ -17,9 +17,10 @@
maybe-make-db.h-redirect:
test -r db.h || echo '#include <@DB_HEADER@>' > db.h
-ET_HEADERS = adm_err.h asn1_err.h kdb5_err.h krb5_err.h
+ET_HEADERS = adm_err.h asn1_err.h kdb5_err.h krb5_err.h k5e1_err.h
K5_ET_HEADERS = \
../lib/krb5/error_tables/krb5_err.h \
+ ../lib/krb5/error_tables/k5e1_err.h \
../lib/krb5/error_tables/kdb5_err.h \
../lib/krb5/error_tables/kv5m_err.h \
../lib/krb5/error_tables/krb524_err.h \
@@ -103,7 +104,7 @@
#
# Build the error table include files:
-# asn1_err.h kdb5_err.h krb5_err.h kv5m_err.h krb524_err.h
+# asn1_err.h kdb5_err.h krb5_err.h k5e1_err.h kv5m_err.h krb524_err.h
$(K5_ET_HEADERS): rebuild-error-tables
: $@
@@ -114,8 +115,8 @@
force:
clean-unix::
- $(RM) krb5/krb5.h krb5_err.h kdb5_err.h kv5m_err.h krb524_err.h \
- asn1_err.h private-and-public-decls krb5.stamp
+ $(RM) krb5/krb5.h krb5_err.h k5e1_err.h kdb5_err.h kv5m_err.h \
+ krb524_err.h asn1_err.h private-and-public-decls krb5.stamp
$(RM) $(ET_HEADERS) autoconf.stamp
clean-windows::
Modified: branches/plugins2/src/include/k5-int.h
===================================================================
--- branches/plugins2/src/include/k5-int.h 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/include/k5-int.h 2010-08-26 23:19:40 UTC (rev 24259)
@@ -1147,6 +1147,8 @@
char * fast_ccache_name;
krb5_ccache out_ccache;
krb5_flags fast_flags;
+ krb5_expire_callback_func *expire_cb;
+ void *expire_data;
} krb5_gic_opt_private;
/*
Modified: branches/plugins2/src/include/krb5/krb5.hin
===================================================================
--- branches/plugins2/src/include/krb5/krb5.hin 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/include/krb5/krb5.hin 2010-08-26 23:19:40 UTC (rev 24259)
@@ -1003,6 +1003,8 @@
#define KRB5_LRQ_ONE_LAST_REQ (-5)
#define KRB5_LRQ_ALL_PW_EXPTIME 6
#define KRB5_LRQ_ONE_PW_EXPTIME (-6)
+#define KRB5_LRQ_ALL_ACCT_EXPTIME 7
+#define KRB5_LRQ_ONE_ACCT_EXPTIME (-7)
/* PADATA types */
#define KRB5_PADATA_NONE 0
@@ -2352,7 +2354,49 @@
/* Fast flags*/
#define KRB5_FAST_REQUIRED 1l<<0 /*!< Require KDC to support FAST*/
+typedef void
+krb5_expire_callback_func(krb5_context context, void *data,
+ krb5_timestamp password_expiration,
+ krb5_timestamp account_expiration,
+ krb5_boolean is_last_req);
+
+/**
+ * Set a callback to receive password and account expiration times.
+ *
+ * This option only applies to krb5_get_init_creds_password(). @a cb will be
+ * invoked if and only if credentials are successfully acquired. The callback
+ * will receive the @a context from the krb5_get_init_creds_password() call and
+ * the @a data argument supplied with this API. The remaining arguments should
+ * be interpreted as follows:
+ *
+ * If @a is_last_req is true, then the KDC reply contained last-req entries
+ * which unambiguously indicated the password expiration, account expiration,
+ * or both. (If either value was not present, the corresponding argument will
+ * be 0.) Furthermore, a non-zero @a password_expiration should be taken as a
+ * suggestion from the KDC that a warning be displayed.
+ *
+ * If @a is_last_req is false, then @a account_expiration will be 0 and @a
+ * password_expiration will contain the expiration time of either the password
+ * or account, or 0 if no expiration time was indicated in the KDC reply. The
+ * callback should independently decide whether to display a password
+ * expiration warning.
+ *
+ * Note that @a cb may be invoked even if credentials are being acquired for
+ * the kadmin/changepw service in order to change the password. It is the
+ * caller's responsibility to avoid displaying a password expiry warning in
+ * this case.
+ *
+ * Setting an expire callback with this API will cause
+ * krb5_get_init_creds_password() not to send password expiry warnings to the
+ * prompter, as it ordinarily may.
+ */
krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_expire_callback(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_expire_callback_func cb,
+ void *data);
+
+krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password(krb5_context context, krb5_creds *creds,
krb5_principal client, char *password,
krb5_prompter_fct prompter, void *data,
Modified: branches/plugins2/src/kdc/do_as_req.c
===================================================================
--- branches/plugins2/src/kdc/do_as_req.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/kdc/do_as_req.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -88,6 +88,17 @@
int, krb5_data *, krb5_principal, krb5_data **,
const char *);
+/* Determine the key-expiration value according to RFC 4120 section 5.4.2. */
+static krb5_timestamp
+get_key_exp(krb5_db_entry *entry)
+{
+ if (entry->expiration == 0)
+ return entry->pw_expiration;
+ if (entry->pw_expiration == 0)
+ return entry->expiration;
+ return min(entry->expiration, entry->pw_expiration);
+}
+
/*ARGSUSED*/
krb5_error_code
process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
@@ -541,7 +552,7 @@
goto errout;
}
reply_encpart.nonce = request->nonce;
- reply_encpart.key_exp = client->expiration;
+ reply_encpart.key_exp = get_key_exp(client);
reply_encpart.flags = enc_tkt_reply.flags;
reply_encpart.server = ticket_reply.server;
Modified: branches/plugins2/src/lib/gssapi/krb5/acquire_cred.c
===================================================================
--- branches/plugins2/src/lib/gssapi/krb5/acquire_cred.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/gssapi/krb5/acquire_cred.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -103,20 +103,19 @@
const gss_OID desired_object,
gss_buffer_t value)
{
- char *new, *old;
+ char *new = NULL, *old;
int err;
err = gss_krb5int_initialize_library();
if (err != 0)
return GSS_S_FAILURE;
- if (value->value == NULL)
- return GSS_S_FAILURE;
+ if (value->value != NULL) {
+ new = strdup((char *)value->value);
+ if (new == NULL)
+ return GSS_S_FAILURE;
+ }
- new = strdup((char *)value->value);
- if (new == NULL)
- return GSS_S_FAILURE;
-
err = k5_mutex_lock(&gssint_krb5_keytab_lock);
if (err) {
free(new);
@@ -125,8 +124,7 @@
old = krb5_gss_keytab;
krb5_gss_keytab = new;
k5_mutex_unlock(&gssint_krb5_keytab_lock);
- if (old != NULL)
- free(old);
+ free(old);
return GSS_S_COMPLETE;
}
Modified: branches/plugins2/src/lib/gssapi/krb5/krb5_gss_glue.c
===================================================================
--- branches/plugins2/src/lib/gssapi/krb5/krb5_gss_glue.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/gssapi/krb5/krb5_gss_glue.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -253,7 +253,7 @@
OM_uint32 minor_status;
gss_buffer_desc req_buffer;
- req_buffer.length = strlen(keytab);
+ req_buffer.length = (keytab == NULL) ? 0 : strlen(keytab);
req_buffer.value = (char *)keytab;
major_status = gssspi_mech_invoke(&minor_status,
Modified: branches/plugins2/src/lib/kadm5/kadm_rpc_xdr.c
===================================================================
--- branches/plugins2/src/lib/kadm5/kadm_rpc_xdr.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/kadm5/kadm_rpc_xdr.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -1021,7 +1021,7 @@
* is safe.
*/
- if (!xdr_u_int(xdrs, (unsigned int *) objp))
+ if (!xdr_int32(xdrs, (int32_t *) objp))
return (FALSE);
return (TRUE);
}
Modified: branches/plugins2/src/lib/krb5/error_tables/Makefile.in
===================================================================
--- branches/plugins2/src/lib/krb5/error_tables/Makefile.in 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/error_tables/Makefile.in 2010-08-26 23:19:40 UTC (rev 24259)
@@ -10,14 +10,15 @@
EHDRDIR=$(BUILDTOP)$(S)include
ETDIR=$(top_srcdir)$(S)util$(S)et
-STLIBOBJS= asn1_err.o kdb5_err.o krb5_err.o \
+STLIBOBJS= asn1_err.o kdb5_err.o krb5_err.o k5e1_err.o \
kv5m_err.o krb524_err.o
-HDRS= asn1_err.h kdb5_err.h krb5_err.h kv5m_err.h krb524_err.h
-OBJS= $(OUTPRE)asn1_err.$(OBJEXT) $(OUTPRE)kdb5_err.$(OBJEXT) $(OUTPRE)krb5_err.$(OBJEXT) \
+HDRS= asn1_err.h kdb5_err.h krb5_err.h k5e1_err.h kv5m_err.h krb524_err.h
+OBJS= $(OUTPRE)asn1_err.$(OBJEXT) $(OUTPRE)kdb5_err.$(OBJEXT) \
+ $(OUTPRE)krb5_err.$(OBJEXT) $(OUTPRE)k5e1_err.$(OBJEXT) \
$(OUTPRE)kv5m_err.$(OBJEXT) $(OUTPRE)krb524_err.$(OBJEXT)
-ETSRCS= asn1_err.c kdb5_err.c krb5_err.c kv5m_err.c krb524_err.c
-SRCS= asn1_err.c kdb5_err.c krb5_err.c kv5m_err.c krb524_err.c
+ETSRCS= asn1_err.c kdb5_err.c krb5_err.c k5e1_err.c kv5m_err.c krb524_err.c
+SRCS= asn1_err.c kdb5_err.c krb5_err.c k5e1_err.c kv5m_err.c krb524_err.c
##DOS##LIBOBJS = $(OBJS)
@@ -30,16 +31,19 @@
$(AWK) -f $(ETDIR)/et_h.awk outfile=asn1_err.h asn1_err.et
$(AWK) -f $(ETDIR)/et_h.awk outfile=kdb5_err.h kdb5_err.et
$(AWK) -f $(ETDIR)/et_h.awk outfile=krb5_err.h krb5_err.et
+ $(AWK) -f $(ETDIR)/et_h.awk outfile=k5e1_err.h k5e1_err.et
$(AWK) -f $(ETDIR)/et_h.awk outfile=kv5m_err.h kv5m_err.et
$(AWK) -f $(ETDIR)/et_h.awk outfile=krb524_err.h krb524_err.et
$(AWK) -f $(ETDIR)/et_c.awk outfile=asn1_err.c asn1_err.et
$(AWK) -f $(ETDIR)/et_c.awk outfile=kdb5_err.c kdb5_err.et
$(AWK) -f $(ETDIR)/et_c.awk outfile=krb5_err.c krb5_err.et
+ $(AWK) -f $(ETDIR)/et_c.awk outfile=k5e1_err.c k5e1_err.et
$(AWK) -f $(ETDIR)/et_c.awk outfile=kv5m_err.c kv5m_err.et
$(AWK) -f $(ETDIR)/et_c.awk outfile=krb524_err.c krb524_err.et
if exist asn1_err.h copy asn1_err.h "$(EHDRDIR)"
if exist kdb5_err.h copy kdb5_err.h "$(EHDRDIR)"
if exist krb5_err.h copy krb5_err.h "$(EHDRDIR)"
+ if exist k5e1_err.h copy k5e1_err.h "$(EHDRDIR)"
if exist kv5m_err.h copy kv5m_err.h "$(EHDRDIR)"
if exist krb524_err.h copy krb524_err.h "$(EHDRDIR)"
@@ -49,6 +53,7 @@
$(OUTPRE)asn1_err.$(OBJEXT): asn1_err.c
$(OUTPRE)kdb5_err.$(OBJEXT): kdb5_err.c
$(OUTPRE)krb5_err.$(OBJEXT): krb5_err.c
+$(OUTPRE)k5e1_err.$(OBJEXT): k5e1_err.c
$(OUTPRE)kv5m_err.$(OBJEXT): kv5m_err.c
$(OUTPRE)krb524_err.$(OBJEXT): krb524_err.c
Copied: branches/plugins2/src/lib/krb5/error_tables/k5e1_err.et (from rev 24258, trunk/src/lib/krb5/error_tables/k5e1_err.et)
===================================================================
--- branches/plugins2/src/lib/krb5/error_tables/k5e1_err.et (rev 0)
+++ branches/plugins2/src/lib/krb5/error_tables/k5e1_err.et 2010-08-26 23:19:40 UTC (rev 24259)
@@ -0,0 +1,33 @@
+#
+# lib/krb5/error_tables/k5e1_err.et
+#
+# Copyright 2010 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+# require a specific license from the United States Government.
+# It is the responsibility of any person or organization contemplating
+# export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission. Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose. It is provided "as is" without express
+# or implied warranty.
+#
+#
+# The Kerberos v5 library error code expansion table (#1).
+# This table exists to hold new libkrb5 error codes since the
+# original krb5 error table is full.
+#
+error_table k5e1
+
+end
Modified: branches/plugins2/src/lib/krb5/krb/Makefile.in
===================================================================
--- branches/plugins2/src/lib/krb5/krb/Makefile.in 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/krb/Makefile.in 2010-08-26 23:19:40 UTC (rev 24259)
@@ -386,6 +386,9 @@
t_etypes: $(T_ETYPES_OBJS) $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o t_etypes $(T_ETYPES_OBJS) $(KRB5_BASE_LIBS)
+t_expire_warn: t_expire_warn.o $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ t_expire_warn.o $(KRB5_BASE_LIBS)
+
TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \
t_princ t_etypes
@@ -426,6 +429,9 @@
$(RUN_SETUP) $(VALGRIND) ./t_princ
$(RUN_SETUP) $(VALGRIND) ./t_etypes
+check-pytests:: t_expire_warn
+ $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS)
+
clean::
$(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \
$(OUTPRE)t_kerb$(EXEEXT) $(OUTPRE)t_kerb.$(OBJEXT) \
Modified: branches/plugins2/src/lib/krb5/krb/gic_opt.c
===================================================================
--- branches/plugins2/src/lib/krb5/krb/gic_opt.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/krb/gic_opt.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -480,3 +480,22 @@
*out_flags = opte->opt_private->fast_flags;
return retval;
}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_expire_callback(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_expire_callback_func cb,
+ void *data)
+{
+ krb5_error_code retval = 0;
+ krb5_gic_opt_ext *opte;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_set_"
+ "expire_callback");
+ if (retval)
+ return retval;
+ opte->opt_private->expire_cb = cb;
+ opte->opt_private->expire_data = data;
+ return retval;
+}
Modified: branches/plugins2/src/lib/krb5/krb/gic_pwd.c
===================================================================
--- branches/plugins2/src/lib/krb5/krb/gic_pwd.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/krb/gic_pwd.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -56,12 +56,10 @@
/* PROMPTER_INVOCATION */
krb5int_set_prompt_types(context, &prompt_type);
- if ((ret = (((*prompter)(context, prompter_data, NULL, NULL,
- 1, &prompt))))) {
- krb5int_set_prompt_types(context, 0);
+ ret = (*prompter)(context, prompter_data, NULL, NULL, 1, &prompt);
+ krb5int_set_prompt_types(context, 0);
+ if (ret)
return(ret);
- }
- krb5int_set_prompt_types(context, 0);
}
if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
@@ -106,6 +104,111 @@
return 0;
}
+/* Return the password expiry time indicated by enc_part2. Set *is_last_req
+ * if the information came from a last_req value. */
+static void
+get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
+ krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
+{
+ krb5_last_req_entry **last_req;
+ krb5_int32 lr_type;
+
+ *pw_exp = 0;
+ *acct_exp = 0;
+ *is_last_req = FALSE;
+
+ /* Look for last-req entries for password or account expiration. */
+ if (enc_part2->last_req) {
+ for (last_req = enc_part2->last_req; *last_req; last_req++) {
+ lr_type = (*last_req)->lr_type;
+ if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
+ *is_last_req = TRUE;
+ *pw_exp = (*last_req)->value;
+ } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
+ *is_last_req = TRUE;
+ *acct_exp = (*last_req)->value;
+ }
+ }
+ }
+
+ /* If we didn't find any, use the ambiguous key_exp field. */
+ if (*is_last_req == FALSE)
+ *pw_exp = enc_part2->key_exp;
+}
+
+/*
+ * Send an appropriate warning prompter if as_reply indicates that the password
+ * is going to expire soon. If an expire callback was provided, use that
+ * instead.
+ */
+static void
+warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
+ krb5_prompter_fct prompter, void *data,
+ const char *in_tkt_service, krb5_kdc_rep *as_reply)
+{
+ krb5_error_code ret;
+ krb5_timestamp pw_exp, acct_exp, now;
+ krb5_boolean is_last_req;
+ krb5_deltat delta;
+ krb5_gic_opt_ext *opte;
+ char ts[256], banner[1024];
+
+ get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
+
+ ret = krb5int_gic_opt_to_opte(context, options, &opte, 0, "");
+ if (ret == 0 && opte->opt_private->expire_cb != NULL) {
+ krb5_expire_callback_func *cb = opte->opt_private->expire_cb;
+ void *cb_data = opte->opt_private->expire_data;
+
+ /* Invoke the expire callback and don't send prompter warnings. */
+ (*cb)(context, cb_data, pw_exp, acct_exp, is_last_req);
+ return;
+ }
+
+ /* Don't warn if the password is being changed. */
+ if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
+ return;
+
+ /*
+ * If the expiry time came from a last_req field, assume the KDC wants us
+ * to warn. Otherwise, warn only if the expiry time is less than a week
+ * from now.
+ */
+ ret = krb5_timeofday(context, &now);
+ if (ret != 0)
+ return;
+ if (!is_last_req &&
+ (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60))
+ return;
+
+ if (!prompter)
+ return;
+
+ ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
+ if (ret != 0)
+ return;
+
+ delta = pw_exp - now;
+ if (delta < 3600) {
+ snprintf(banner, sizeof(banner),
+ "Warning: Your password will expire in less than one hour "
+ "on %s", ts);
+ } else if (delta < 86400*2) {
+ snprintf(banner, sizeof(banner),
+ "Warning: Your password will expire in %d hour%s on %s",
+ delta / 3600, delta < 7200 ? "" : "s", ts);
+ } else {
+ snprintf(banner, sizeof(banner),
+ "Warning: Your password will expire in %d days on %s",
+ delta / 86400, ts);
+ }
+
+ /* PROMPTER_INVOCATION */
+ (*prompter)(context, data, 0, banner, 0, 0);
+}
+
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password(krb5_context context,
krb5_creds *creds,
@@ -263,12 +366,12 @@
/* PROMPTER_INVOCATION */
krb5int_set_prompt_types(context, prompt_types);
- if ((ret = ((*prompter)(context, data, 0, banner,
- sizeof(prompt)/sizeof(prompt[0]), prompt))))
+ ret = (*prompter)(context, data, 0, banner,
+ sizeof(prompt)/sizeof(prompt[0]), prompt);
+ krb5int_set_prompt_types(context, 0);
+ if (ret)
goto cleanup;
- krb5int_set_prompt_types(context, 0);
-
if (strcmp(pw0.data, pw1.data) != 0) {
ret = KRB5_LIBOS_BADPWDMATCH;
snprintf(banner, sizeof(banner),
@@ -334,84 +437,14 @@
start_time, in_tkt_service, options,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
+ if (ret)
+ goto cleanup;
cleanup:
- krb5int_set_prompt_types(context, 0);
- /* if getting the password was successful, then check to see if the
- password is about to expire, and warn if so */
+ if (ret == 0)
+ warn_pw_expiry(context, options, prompter, data, in_tkt_service,
+ as_reply);
- if (ret == 0) {
- krb5_timestamp now;
- krb5_last_req_entry **last_req;
- int hours;
-
- /* XXX 7 days should be configurable. This is all pretty ad hoc,
- and could probably be improved if I was willing to screw around
- with timezones, etc. */
-
- if (prompter &&
- (!in_tkt_service ||
- (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
- ((ret = krb5_timeofday(context, &now)) == 0) &&
- as_reply->enc_part2->key_exp &&
- ((hours = ((as_reply->enc_part2->key_exp-now)/(60*60))) <= 7*24) &&
- (hours >= 0)) {
- if (hours < 1)
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in less than one hour.");
- else if (hours <= 48)
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in %d hour%s.",
- hours, (hours == 1)?"":"s");
- else
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in %d days.",
- hours/24);
-
- /* ignore an error here */
- /* PROMPTER_INVOCATION */
- (*prompter)(context, data, 0, banner, 0, 0);
- } else if (prompter &&
- (!in_tkt_service ||
- (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
- as_reply->enc_part2 && as_reply->enc_part2->last_req) {
- /*
- * Check the last_req fields
- */
-
- for (last_req = as_reply->enc_part2->last_req; *last_req; last_req++)
- if ((*last_req)->lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
- (*last_req)->lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
- krb5_deltat delta;
- char ts[256];
-
- if ((ret = krb5_timeofday(context, &now)))
- break;
-
- if ((ret = krb5_timestamp_to_string((*last_req)->value,
- ts, sizeof(ts))))
- break;
-
- delta = (*last_req)->value - now;
- if (delta < 3600)
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in less than one hour on %s",
- ts);
- else if (delta < 86400*2)
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in %d hour%s on %s",
- delta / 3600, delta < 7200 ? "" : "s", ts);
- else
- snprintf(banner, sizeof(banner),
- "Warning: Your password will expire in %d days on %s",
- delta / 86400, ts);
- /* ignore an error here */
- /* PROMPTER_INVOCATION */
- (*prompter)(context, data, 0, banner, 0, 0);
- }
- }
- }
-
if (chpw_opts)
krb5_get_init_creds_opt_free(context, chpw_opts);
memset(pw0array, 0, sizeof(pw0array));
Modified: branches/plugins2/src/lib/krb5/krb/rd_req_dec.c
===================================================================
--- branches/plugins2/src/lib/krb5/krb/rd_req_dec.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/krb/rd_req_dec.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -44,7 +44,14 @@
*
* server specifies the expected server's name for the ticket; if NULL, then
* any server will be accepted if the key can be found, and the caller should
- * verify that the principal is something it trusts.
+ * verify that the principal is something it trusts. With the exception of the
+ * kdb keytab, the ticket's server field need not match the name passed in for
+ * server. All that is required is that the ticket be encrypted with a key
+ * from the keytab associated with the specified server principal. This
+ * permits the KDC to have a set of aliases for the server without keeping
+ * this information consistent with the server. So, when server is non-null,
+ * the principal expected by the application needs to be consistent with the
+ * local keytab, but not with the informational name in the ticket.
*
* rcache specifies a replay detection cache used to store authenticators and
* server names
Copied: branches/plugins2/src/lib/krb5/krb/t_expire_warn.c (from rev 24258, trunk/src/lib/krb5/krb/t_expire_warn.c)
===================================================================
--- branches/plugins2/src/lib/krb5/krb/t_expire_warn.c (rev 0)
+++ branches/plugins2/src/lib/krb5/krb/t_expire_warn.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -0,0 +1,90 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * lib/krb5/krb/t_expire_warn.c
+ *
+ * Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Test harness for password expiration warnings.
+ */
+
+#include "k5-int.h"
+
+static int exp_dummy, prompt_dummy;
+
+static krb5_error_code
+prompter_cb(krb5_context ctx, void *data, const char *name,
+ const char *banner, int num_prompts, krb5_prompt prompts[])
+{
+ /* Not expecting any actual prompts, only banners. */
+ assert(num_prompts == 0);
+ assert(banner != NULL);
+ printf("Prompter: %s\n", banner);
+ return 0;
+}
+
+static void
+expire_cb(krb5_context ctx, void *data, krb5_timestamp password_expiration,
+ krb5_timestamp account_expiration, krb5_boolean is_last_req)
+{
+ printf("password_expiration = %ld\n", (long)password_expiration);
+ printf("account_expiration = %ld\n", (long)account_expiration);
+ printf("is_last_req = %d\n", (int)is_last_req);
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context ctx;
+ krb5_get_init_creds_opt *opt;
+ char *user, *password, *service = NULL;
+ krb5_boolean use_cb;
+ krb5_principal client;
+ krb5_creds creds;
+
+ if (argc < 4) {
+ fprintf(stderr, "Usage: %s username password {1|0} [service]\n",
+ argv[0]);
+ return 1;
+ }
+ user = argv[1];
+ password = argv[2];
+ use_cb = atoi(argv[3]);
+ if (argc >= 5)
+ service = argv[4];
+
+ assert(krb5_init_context(&ctx) == 0);
+ assert(krb5_get_init_creds_opt_alloc(ctx, &opt) == 0);
+ if (use_cb) {
+ assert(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
+ &exp_dummy) == 0);
+ }
+ assert(krb5_parse_name(ctx, user, &client) == 0);
+ assert(krb5_get_init_creds_password(ctx, &creds, client, password,
+ prompter_cb, &prompt_dummy, 0, service,
+ opt) == 0);
+ krb5_get_init_creds_opt_free(ctx, opt);
+ krb5_free_principal(ctx, client);
+ krb5_free_cred_contents(ctx, &creds);
+ return 0;
+}
Copied: branches/plugins2/src/lib/krb5/krb/t_expire_warn.py (from rev 24258, trunk/src/lib/krb5/krb/t_expire_warn.py)
===================================================================
--- branches/plugins2/src/lib/krb5/krb/t_expire_warn.py (rev 0)
+++ branches/plugins2/src/lib/krb5/krb/t_expire_warn.py 2010-08-26 23:19:40 UTC (rev 24259)
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 by the Massachusetts Institute of Technology.
+# All rights reserved.
+#
+# Export of this software from the United States of America may
+# require a specific license from the United States Government.
+# It is the responsibility of any person or organization contemplating
+# export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission. Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose. It is provided "as is" without express
+# or implied warranty.
+
+#!/usr/bin/python
+from k5test import *
+
+# Create a bare-bones KDC.
+realm = K5Realm(create_user=False, create_host=False, start_kadmind=False)
+
+# Create principals with various password expirations.
+realm.run_kadminl('addprinc -pw pass noexpire')
+realm.run_kadminl('addprinc -pw pass -pwexpire "30 minutes" minutes')
+realm.run_kadminl('addprinc -pw pass -pwexpire "12 hours" hours')
+realm.run_kadminl('addprinc -pw pass -pwexpire "3 days" days')
+
+# Check for expected prompter warnings when no expire callback is used.
+output = realm.run_as_client(['./t_expire_warn', 'noexpire', 'pass', '0'])
+if output:
+ fail('Unexpected output for noexpire')
+output = realm.run_as_client(['./t_expire_warn', 'minutes', 'pass', '0'])
+if ' less than one hour on ' not in output:
+ fail('Expected warning not seen for minutes')
+output = realm.run_as_client(['./t_expire_warn', 'hours', 'pass', '0'])
+if ' hours on ' not in output:
+ fail('Expected warning not seen for hours')
+output = realm.run_as_client(['./t_expire_warn', 'days', 'pass', '0'])
+if ' days on ' not in output:
+ fail('Expected warning not seen for days')
+
+# Check for expected expire callback behavior. These tests are
+# carefully agnostic about whether the KDC supports last_req fields,
+# and could be made more specific if last_req support is added.
+output = realm.run_as_client(['./t_expire_warn', 'noexpire', 'pass', '1'])
+if 'password_expiration = 0\n' not in output or \
+ 'account_expiration = 0\n' not in output or \
+ 'is_last_req = ' not in output:
+ fail('Expected callback output not seen for noexpire')
+output = realm.run_as_client(['./t_expire_warn', 'days', 'pass', '1'])
+if 'password_expiration = ' not in output or \
+ 'password_expiration = 0\n' in output:
+ fail('Expected non-zero password expiration not seen for days')
+
+success('Password expiration warning tests.')
Modified: branches/plugins2/src/lib/krb5/libkrb5.exports
===================================================================
--- branches/plugins2/src/lib/krb5/libkrb5.exports 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/krb5/libkrb5.exports 2010-08-26 23:19:40 UTC (rev 24259)
@@ -350,6 +350,7 @@
krb5_get_init_creds_opt_set_canonicalize
krb5_get_init_creds_opt_set_change_password_prompt
krb5_get_init_creds_opt_set_etype_list
+krb5_get_init_creds_opt_set_expire_callback
krb5_get_init_creds_opt_set_fast_ccache_name
krb5_get_init_creds_opt_set_fast_flags
krb5_get_init_creds_opt_set_forwardable
Modified: branches/plugins2/src/lib/rpc/xdr.c
===================================================================
--- branches/plugins2/src/lib/rpc/xdr.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/lib/rpc/xdr.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -145,7 +145,7 @@
if (!XDR_GETLONG(xdrs, (long *) &l))
return (FALSE);
- if (l > UINT_MAX)
+ if ((uint32_t)l > UINT_MAX)
return (FALSE);
*up = (u_int) l;
Modified: branches/plugins2/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
===================================================================
--- branches/plugins2/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -2087,7 +2087,7 @@
goto cleanup;
if (attr_present == TRUE) {
- if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) {
+ if (mask & KDB_PRINC_EXPIRE_TIME_ATTR) {
if (expiretime < entry->expiration)
entry->expiration = expiretime;
} else {
@@ -2127,7 +2127,7 @@
if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0)
goto cleanup;
- if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) {
+ if (mask & KDB_PWD_EXPIRE_TIME_ATTR) {
if ((last_pw_changed + pw_max_life) < entry->pw_expiration)
entry->pw_expiration = last_pw_changed + pw_max_life;
} else
Modified: branches/plugins2/src/util/k5test.py
===================================================================
--- branches/plugins2/src/util/k5test.py 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/util/k5test.py 2010-08-26 23:19:40 UTC (rev 24259)
@@ -119,7 +119,7 @@
* start_kdc=False: Don't start the KDC. Implies get_creds=False.
-* start_kadmin=False: Don't start kadmind.
+* start_kadmind=False: Don't start kadmind.
* get_creds=False: Don't get user credentials.
Modified: svn:ignore
- obj
darwin.exports
*.dylib
prof_err.h
prtest
prof_err.c
profile.h
test_parse
test_profile
lib*.so.*
Makefile
*.so
OBJS.*
binutils.versions
test?.ini
lib*.a
*.bak
profile_tcl
+ obj
darwin.exports
*.dylib
prof_err.h
prtest
prof_err.c
profile.h
test_parse
test_profile
test_include_dir
lib*.so.*
Makefile
*.so
OBJS.*
binutils.versions
test?.ini
lib*.a
*.bak
profile_tcl
Modified: branches/plugins2/src/util/profile/prof_err.et
===================================================================
--- branches/plugins2/src/util/profile/prof_err.et 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/util/profile/prof_err.et 2010-08-26 23:19:40 UTC (rev 24259)
@@ -60,7 +60,13 @@
error_code PROF_BAD_BOOLEAN, "Invalid boolean value"
error_code PROF_BAD_INTEGER, "Invalid integer value"
+#
+# new error codes added at end to avoid changing values
+#
error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t"
+error_code PROF_FAIL_INCLUDE_FILE,
+ "Included profile file could not be read"
+error_code PROF_FAIL_INCLUDE_DIR,
+ "Included profile directory could not be read"
-
end
Modified: branches/plugins2/src/util/profile/prof_init.c
===================================================================
--- branches/plugins2/src/util/profile/prof_init.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/util/profile/prof_init.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -27,7 +27,7 @@
const_profile_filespec_t *fs;
profile_t profile;
prf_file_t new_file, last = 0;
- errcode_t retval = 0;
+ errcode_t retval = 0, access_retval = 0;
profile = malloc(sizeof(struct _profile_t));
if (!profile)
@@ -43,9 +43,14 @@
for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
retval = profile_open_file(*fs, &new_file);
/* if this file is missing, skip to the next */
- if (retval == ENOENT || retval == EACCES || retval == EPERM) {
+ if (retval == ENOENT) {
continue;
}
+ /* If we can't read this file, remember it but keep going. */
+ if (retval == EACCES || retval == EPERM) {
+ access_retval = retval;
+ continue;
+ }
if (retval) {
profile_release(profile);
return retval;
@@ -58,11 +63,11 @@
}
/*
* If last is still null after the loop, then all the files were
- * missing, so return the appropriate error.
+ * missing or unreadable, so return the appropriate error.
*/
if (!last) {
profile_release(profile);
- return ENOENT;
+ return access_retval ? access_retval : ENOENT;
}
}
Modified: branches/plugins2/src/util/profile/prof_parse.c
===================================================================
--- branches/plugins2/src/util/profile/prof_parse.c 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/util/profile/prof_parse.c 2010-08-26 23:19:40 UTC (rev 24259)
@@ -1,6 +1,7 @@
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "prof_int.h"
+#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
@@ -8,6 +9,7 @@
#endif
#include <errno.h>
#include <ctype.h>
+#include <dirent.h>
#define SECTION_SEP_CHAR '/'
@@ -22,6 +24,8 @@
struct profile_node *current_section;
};
+static errcode_t parse_file(FILE *f, struct parse_state *state);
+
static char *skip_over_blanks(char *cp)
{
while (*cp && isspace((int) (*cp)))
@@ -33,7 +37,7 @@
{
char *p = line + strlen(line);
while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
- *p-- = 0;
+ *--p = 0;
}
static void parse_quoted_string(char *str)
@@ -66,14 +70,6 @@
}
-static errcode_t parse_init_state(struct parse_state *state)
-{
- state->state = STATE_INIT_COMMENT;
- state->group_level = 0;
-
- return profile_create_node("(root)", 0, &state->root_section);
-}
-
static errcode_t parse_std_line(char *line, struct parse_state *state)
{
char *cp, ch, *tag, *value;
@@ -201,10 +197,83 @@
return 0;
}
+/* Open and parse an included profile file. */
+static errcode_t parse_include_file(char *filename, struct parse_state *state)
+{
+ FILE *fp;
+ errcode_t retval = 0;
+ struct parse_state incstate;
+
+ /* Create a new state so that fragments are syntactically independent,
+ * sharing the root section with the existing state. */
+ incstate.state = STATE_INIT_COMMENT;
+ incstate.group_level = 0;
+ incstate.root_section = state->root_section;
+ incstate.current_section = NULL;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ return PROF_FAIL_INCLUDE_FILE;
+ retval = parse_file(fp, &incstate);
+ fclose(fp);
+ return retval;
+}
+
+/* Return non-zero if filename contains only alphanumeric characters, dashes,
+ * and underscores. */
+static int valid_name(const char *filename)
+{
+ const char *p;
+
+ for (p = filename; *p != '\0'; p++) {
+ if (!isalnum((unsigned char)*p) && *p != '-' && *p != '_')
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Include files within dirname. Only files with names consisting entirely of
+ * alphanumeric chracters, dashes, and underscores are included, in order to
+ * avoid including editor backup files, .rpmsave files, and the like.
+ */
+static errcode_t parse_include_dir(char *dirname, struct parse_state *state)
+{
+ DIR *dir;
+ char *pathname;
+ errcode_t retval;
+ struct dirent *ent;
+
+ dir = opendir(dirname);
+ if (dir == NULL)
+ return PROF_FAIL_INCLUDE_DIR;
+ while ((ent = readdir(dir)) != NULL) {
+ if (!valid_name(ent->d_name))
+ continue;
+ if (asprintf(&pathname, "%s/%s", dirname, ent->d_name) < 0)
+ return ENOMEM;
+ retval = parse_include_file(pathname, state);
+ free(pathname);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
static errcode_t parse_line(char *line, struct parse_state *state)
{
char *cp;
+ if (strncmp(line, "include", 7) == 0 && isspace(line[7])) {
+ cp = skip_over_blanks(line + 7);
+ strip_line(cp);
+ return parse_include_file(cp, state);
+ }
+ if (strncmp(line, "includedir", 10) == 0 && isspace(line[10])) {
+ cp = skip_over_blanks(line + 10);
+ strip_line(cp);
+ return parse_include_dir(cp, state);
+ }
switch (state->state) {
case STATE_INIT_COMMENT:
if (line[0] != '[')
@@ -221,29 +290,22 @@
return 0;
}
-errcode_t profile_parse_file(FILE *f, struct profile_node **root)
+static errcode_t parse_file(FILE *f, struct parse_state *state)
{
#define BUF_SIZE 2048
char *bptr;
errcode_t retval;
- struct parse_state state;
bptr = malloc (BUF_SIZE);
if (!bptr)
return ENOMEM;
- retval = parse_init_state(&state);
- if (retval) {
- free (bptr);
- return retval;
- }
while (!feof(f)) {
if (fgets(bptr, BUF_SIZE, f) == NULL)
break;
#ifndef PROFILE_SUPPORTS_FOREIGN_NEWLINES
- retval = parse_line(bptr, &state);
+ retval = parse_line(bptr, state);
if (retval) {
- profile_free_node(state.root_section);
free (bptr);
return retval;
}
@@ -286,9 +348,8 @@
/* parse_line modifies contents of p */
newp = p + strlen (p) + 1;
- retval = parse_line (p, &state);
+ retval = parse_line (p, state);
if (retval) {
- profile_free_node(state.root_section);
free (bptr);
return retval;
}
@@ -298,12 +359,35 @@
}
#endif
}
- *root = state.root_section;
free (bptr);
return 0;
}
+errcode_t profile_parse_file(FILE *f, struct profile_node **root)
+{
+ struct parse_state state;
+ errcode_t retval;
+
+ *root = NULL;
+
+ /* Initialize parsing state with a new root node. */
+ state.state = STATE_INIT_COMMENT;
+ state.group_level = 0;
+ state.current_section = NULL;
+ retval = profile_create_node("(root)", 0, &state.root_section);
+ if (retval)
+ return retval;
+
+ retval = parse_file(f, &state);
+ if (retval) {
+ profile_free_node(state.root_section);
+ return retval;
+ }
+ *root = state.root_section;
+ return 0;
+}
+
/*
* Return TRUE if the string begins or ends with whitespace
*/
Modified: branches/plugins2/src/util/profile/prof_test1
===================================================================
--- branches/plugins2/src/util/profile/prof_test1 2010-08-26 16:59:37 UTC (rev 24258)
+++ branches/plugins2/src/util/profile/prof_test1 2010-08-26 23:19:40 UTC (rev 24259)
@@ -147,8 +147,97 @@
puts "OK: test3: Clearing relation and adding one entry yields correct count."
}
+# Exercise the include and includedir directives.
+proc test4 {} {
+ global wd verbose
+
+ # Test expected error message when including nonexistent file.
+ catch [file delete $wd/testinc.ini]
+ exec echo "include does-not-exist" >$wd/testinc.ini
+ catch { profile_init_path $wd/testinc.ini } err
+ if $verbose { puts "Got error message $err" }
+ if { $err ne "Included profile file could not be read" } {
+ puts stderr "Error: test4: Did not get expected error when including nonexistent file."
+ exit 1
+ }
+
+ # Test expected error message when including nonexistent directory.
+ catch [file delete $wd/testinc.ini]
+ exec echo "includedir does-not-exist" >$wd/testinc.ini
+ catch { profile_init_path $wd/testinc.ini } err
+ if $verbose { puts "Got error message $err" }
+ if { $err ne "Included profile directory could not be read" } {
+ puts stderr "Error: test4: Did not get expected error when including nonexistent directory."
+ exit 1
+ }
+
+ # Test including a file.
+ catch [file delete $wd/testinc.ini]
+ exec echo "include $wd/test2.ini" >$wd/testinc.ini
+ set p [profile_init_path $wd/testinc.ini]
+ set x [profile_get_values $p {{test section 1} bar}]
+ if $verbose { puts "Read $x from included profile" }
+ if { [lindex $x 0] ne "foo" } {
+ puts stderr "Error: test4: Did not get expected result from included profile."
+ exit 1
+ }
+ profile_release $p
+
+ # Test including a directory. (Put two copies of test2.ini inside
+ # it and check that we get two values for one of the variables.)
+ catch [file delete -force $wd/test_include_dir]
+ exec mkdir $wd/test_include_dir
+ exec cp $wd/test2.ini $wd/test_include_dir/a
+ exec cp $wd/test2.ini $wd/test_include_dir/b
+ catch [file delete $wd/testinc.ini]
+ exec echo "includedir $wd/test_include_dir" >$wd/testinc.ini
+ set p [profile_init_path $wd/testinc.ini]
+ set x [profile_get_values $p {{test section 1} bar}]
+ if $verbose { puts "Read $x from included directory" }
+ if { $x ne "foo foo" } {
+ puts stderr, "Error: test4: Did not get expected result from included directory."
+ exit 1
+ }
+ profile_release $p
+
+ puts "OK: test4: include and includedir directives"
+}
+
+proc test5 {} {
+ global wd verbose
+
+ # Test syntactic independence of included profile files.
+ catch [file delete $wd/testinc.ini]
+ set f [open "$wd/testinc.ini" w]
+ puts $f {[sec1]}
+ puts $f "var = {"
+ puts $f "a = 1"
+ puts $f "include testinc2.ini"
+ puts $f "c = 3"
+ puts $f "}"
+ close $f
+ catch [file delete $wd/testinc2.ini]
+ set f [open "$wd/testinc2.ini" w]
+ puts $f {[sec2]}
+ puts $f "b = 2"
+ close $f
+ set p [profile_init_path $wd/testinc.ini]
+ set a [profile_get_values $p {sec1 var a}]
+ set b [profile_get_values $p {sec2 b}]
+ set c [profile_get_values $p {sec1 var c}]
+ if $verbose { puts "Read values [concat $a $b $c] from profile" }
+ if { $a != 1 || $b != 2 || $c != 3 } {
+ puts stderr, "Error: test5: Wrong results from profile"
+ exit 1
+ }
+
+ puts "OK: test5: syntax independence of included files"
+}
+
test1
test2
test3
+test4
+test5
exit 0
Property changes on: branches/plugins2/src/util/profile
___________________________________________________________________
More information about the cvs-krb5
mailing list