diff options
author | Ken Raeburn <raeburn@mit.edu> | 2008-06-24 05:04:29 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@mit.edu> | 2008-06-24 05:04:29 +0000 |
commit | 5661d1290f74312a405db970aea097da77706f71 (patch) | |
tree | 0ab69c8078ef3275b99a3ad27f3592b607e43f70 /src/lib/kdb | |
parent | 6879f371402854465e5276d36e4792938906097f (diff) | |
download | krb5-5661d1290f74312a405db970aea097da77706f71.tar.gz krb5-5661d1290f74312a405db970aea097da77706f71.tar.xz krb5-5661d1290f74312a405db970aea097da77706f71.zip |
Merge from branch sun-iprop
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20465 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/kdb')
-rw-r--r-- | src/lib/kdb/Makefile.in | 66 | ||||
-rw-r--r-- | src/lib/kdb/iprop.x | 223 | ||||
-rw-r--r-- | src/lib/kdb/iprop_xdr.c | 351 | ||||
-rw-r--r-- | src/lib/kdb/kdb5.c | 234 | ||||
-rw-r--r-- | src/lib/kdb/kdb_convert.c | 1017 | ||||
-rw-r--r-- | src/lib/kdb/kdb_log.c | 928 | ||||
-rw-r--r-- | src/lib/kdb/libkdb5.exports | 9 |
7 files changed, 2795 insertions, 33 deletions
diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index 65ee8e7704..9935a450a0 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -20,8 +20,9 @@ RELDIR=kdb SHLIB_EXPDEPS = \ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(TOPLIBD)/libgssrpc$(SHLIBEXT) \ $(TOPLIBD)/libkrb5$(SHLIBEXT) -SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(DL_LIB) $(LIBS) +SHLIB_EXPLIBS=-lgssrpc -lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(DL_LIB) $(LIBS) SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) @@ -35,6 +36,9 @@ SRCS= \ $(srcdir)/kdb_default.c \ $(srcdir)/kdb_cpw.c \ adb_err.c \ + $(srcdir)/iprop_xdr.c \ + $(srcdir)/kdb_convert.c \ + $(srcdir)/kdb_log.c \ $(srcdir)/keytab.c STOBJLISTS=OBJS.ST @@ -45,6 +49,9 @@ STLIBOBJS= \ kdb_default.o \ kdb_cpw.o \ adb_err.o \ + iprop_xdr.o \ + kdb_convert.o \ + kdb_log.o \ keytab.o all-unix:: all-liblinks @@ -61,14 +68,22 @@ clean-unix:: clean-liblinks clean-libs clean-libobjs # the Makefile.in file # kdb5.so kdb5.po $(OUTPRE)kdb5.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ - $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/gssrpc/auth.h \ + $(SRCTOP)/include/gssrpc/auth_gss.h $(SRCTOP)/include/gssrpc/auth_unix.h \ + $(SRCTOP)/include/gssrpc/clnt.h $(SRCTOP)/include/gssrpc/rename.h \ + $(SRCTOP)/include/gssrpc/rpc.h $(SRCTOP)/include/gssrpc/rpc_msg.h \ + $(SRCTOP)/include/gssrpc/svc.h $(SRCTOP)/include/gssrpc/svc_auth.h \ + $(SRCTOP)/include/gssrpc/xdr.h $(SRCTOP)/include/iprop.h \ + $(SRCTOP)/include/iprop_hdr.h $(SRCTOP)/include/k5-err.h \ $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ - $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ - $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \ - $(SRCTOP)/include/socket-utils.h adb_err.h kdb5.c kdb5.h + $(SRCTOP)/include/kdb_log.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + adb_err.h kdb5.c kdb5.h encrypt_key.so encrypt_key.po $(OUTPRE)encrypt_key.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ @@ -107,6 +122,47 @@ kdb_cpw.so kdb_cpw.po $(OUTPRE)kdb_cpw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h $(SRCTOP)/include/socket-utils.h kdb_cpw.c adb_err.so adb_err.po $(OUTPRE)adb_err.$(OBJEXT): $(COM_ERR_DEPS) \ adb_err.c +iprop_xdr.so iprop_xdr.po $(OUTPRE)iprop_xdr.$(OBJEXT): \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ + $(SRCTOP)/include/gssrpc/auth.h $(SRCTOP)/include/gssrpc/auth_gss.h \ + $(SRCTOP)/include/gssrpc/auth_unix.h $(SRCTOP)/include/gssrpc/clnt.h \ + $(SRCTOP)/include/gssrpc/rename.h $(SRCTOP)/include/gssrpc/rpc.h \ + $(SRCTOP)/include/gssrpc/rpc_msg.h $(SRCTOP)/include/gssrpc/svc.h \ + $(SRCTOP)/include/gssrpc/svc_auth.h $(SRCTOP)/include/gssrpc/xdr.h \ + $(SRCTOP)/include/iprop.h iprop_xdr.c +kdb_convert.so kdb_convert.po $(OUTPRE)kdb_convert.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/gssrpc/auth.h $(SRCTOP)/include/gssrpc/auth_gss.h \ + $(SRCTOP)/include/gssrpc/auth_unix.h $(SRCTOP)/include/gssrpc/clnt.h \ + $(SRCTOP)/include/gssrpc/rename.h $(SRCTOP)/include/gssrpc/rpc.h \ + $(SRCTOP)/include/gssrpc/rpc_msg.h $(SRCTOP)/include/gssrpc/svc.h \ + $(SRCTOP)/include/gssrpc/svc_auth.h $(SRCTOP)/include/gssrpc/xdr.h \ + $(SRCTOP)/include/iprop.h $(SRCTOP)/include/iprop_hdr.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int-pkinit.h \ + $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \ + $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \ + $(SRCTOP)/include/socket-utils.h kdb_convert.c +kdb_log.so kdb_log.po $(OUTPRE)kdb_log.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/gssrpc/auth.h \ + $(SRCTOP)/include/gssrpc/auth_gss.h $(SRCTOP)/include/gssrpc/auth_unix.h \ + $(SRCTOP)/include/gssrpc/clnt.h $(SRCTOP)/include/gssrpc/rename.h \ + $(SRCTOP)/include/gssrpc/rpc.h $(SRCTOP)/include/gssrpc/rpc_msg.h \ + $(SRCTOP)/include/gssrpc/svc.h $(SRCTOP)/include/gssrpc/svc_auth.h \ + $(SRCTOP)/include/gssrpc/xdr.h $(SRCTOP)/include/iprop.h \ + $(SRCTOP)/include/iprop_hdr.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/kdb_log.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + kdb5.h kdb_log.c keytab.so keytab.po $(OUTPRE)keytab.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h \ diff --git a/src/lib/kdb/iprop.x b/src/lib/kdb/iprop.x new file mode 100644 index 0000000000..840e7a2e58 --- /dev/null +++ b/src/lib/kdb/iprop.x @@ -0,0 +1,223 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* %#pragma ident "@(#)iprop.x 1.2 04/02/20 SMI" */ + +/* + * Main source: + * lib/kdb/iprop.x + * + * Generated files: + * lib/kdb/iprop_xdr.c + * include/iprop.h + * slave/kpropd_rpc.c (clnt) + * + * Derived files: + * kadmin/server/ipropd_svc.c + */ + +#ifdef RPC_XDR +%#include "iprop.h" +#endif /* RPC_XDR */ + +/* + * Initial declarations + */ + +#ifndef RPC_HDR +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +/*typedef hyper int64_t;*/ +/*typedef unsigned hyper uint64_t;*/ +#endif /* !RPC_HDR */ + +typedef opaque utf8str_t<>; + +/* + * Transaction log serial no. + */ +typedef uint32_t kdb_sno_t; + +/* Timestamp */ +struct kdbe_time_t { + uint32_t seconds; + uint32_t useconds; +}; + +/* Key Data */ +struct kdbe_key_t { + int32_t k_ver; /* Version */ + int32_t k_kvno; /* Key version no. */ + int32_t k_enctype<>; + utf8str_t k_contents<>; +}; + +/* Content data */ +struct kdbe_data_t { + int32_t k_magic; + utf8str_t k_data; +}; + +/* Principal Data */ +struct kdbe_princ_t { + utf8str_t k_realm; + kdbe_data_t k_components<>; + int32_t k_nametype; +}; + +/* TL data (pre-auth specific data) */ +struct kdbe_tl_t { + int16_t tl_type; + opaque tl_data<>; +}; + +/* Structure to store pwd history */ +typedef kdbe_key_t kdbe_pw_hist_t<>; + +/* Basic KDB entry attributes */ +enum kdbe_attr_type_t { + AT_ATTRFLAGS = 0, + AT_MAX_LIFE = 1, + AT_MAX_RENEW_LIFE = 2, + AT_EXP = 3, + AT_PW_EXP = 4, + AT_LAST_SUCCESS = 5, + AT_LAST_FAILED = 6, + AT_FAIL_AUTH_COUNT = 7, + AT_PRINC = 8, + AT_KEYDATA = 9, + AT_TL_DATA = 10, + AT_LEN = 11, + AT_MOD_PRINC = 12, + AT_MOD_TIME = 13, + AT_MOD_WHERE = 14, + AT_PW_LAST_CHANGE = 15, + AT_PW_POLICY = 16, + AT_PW_POLICY_SWITCH = 17, + AT_PW_HIST_KVNO = 18, + AT_PW_HIST = 19 +}; + +/* KDB entry, Attribute=value */ +union kdbe_val_t switch (kdbe_attr_type_t av_type) { +case AT_ATTRFLAGS: + uint32_t av_attrflags; +case AT_MAX_LIFE: + uint32_t av_max_life; +case AT_MAX_RENEW_LIFE: + uint32_t av_max_renew_life; +case AT_EXP: + uint32_t av_exp; +case AT_PW_EXP: + uint32_t av_pw_exp; +case AT_LAST_SUCCESS: + uint32_t av_last_success; +case AT_LAST_FAILED: + uint32_t av_last_failed; +case AT_FAIL_AUTH_COUNT: + uint32_t av_fail_auth_count; +case AT_PRINC: + kdbe_princ_t av_princ; +case AT_KEYDATA: + kdbe_key_t av_keydata<>; /* array of keys */ +case AT_TL_DATA: + kdbe_tl_t av_tldata<>; /* array of TL data */ +case AT_LEN: + int16_t av_len; +case AT_PW_LAST_CHANGE: + uint32_t av_pw_last_change; +case AT_MOD_PRINC: + kdbe_princ_t av_mod_princ; +case AT_MOD_TIME: + uint32_t av_mod_time; +case AT_MOD_WHERE: + utf8str_t av_mod_where; +case AT_PW_POLICY: + utf8str_t av_pw_policy; +case AT_PW_POLICY_SWITCH: + bool av_pw_policy_switch; +case AT_PW_HIST_KVNO: + uint32_t av_pw_hist_kvno; +case AT_PW_HIST: + kdbe_pw_hist_t av_pw_hist<>; /* array of pw history */ +default: + opaque av_extension<>; /* futures */ +}; + +typedef kdbe_val_t kdbe_t<>; /* Array of attr/val makes a KDB entry */ + +/* + * Incremental update + */ +struct kdb_incr_update_t { + utf8str_t kdb_princ_name; /* Principal name */ + kdb_sno_t kdb_entry_sno; /* Serial # of entry */ + kdbe_time_t kdb_time; /* Timestamp of update */ + kdbe_t kdb_update; /* Attributes modified */ + bool kdb_deleted; /* Is this update a DELETION ? */ + bool kdb_commit; /* Is the entry committed or not ? */ + utf8str_t kdb_kdcs_seen_by<>; /* Names of slaves that have */ + /* seen this update - for */ + /* future use */ + opaque kdb_futures<>; /* futures */ +}; + +/* + * Update log body + */ +typedef kdb_incr_update_t kdb_ulog_t<>; + +enum update_status_t { + UPDATE_OK = 0, + UPDATE_ERROR = 1, + UPDATE_FULL_RESYNC_NEEDED = 2, + UPDATE_BUSY = 3, + UPDATE_NIL = 4, + UPDATE_PERM_DENIED = 5 +}; + +struct kdb_last_t { + kdb_sno_t last_sno; + kdbe_time_t last_time; +}; + +struct kdb_incr_result_t { + kdb_last_t lastentry; + kdb_ulog_t updates; + update_status_t ret; +}; + +struct kdb_fullresync_result_t { + kdb_last_t lastentry; + update_status_t ret; +}; + +program KRB5_IPROP_PROG { + version KRB5_IPROP_VERS { + /* + * NULL procedure + */ + void + IPROP_NULL(void) = 0; + + /* + * Keep waiting for and get next incremental update(s) + * + * Will return latest kdb_vers on the master (if different), + * alongwith return value and affected db entries. + */ + kdb_incr_result_t + IPROP_GET_UPDATES(kdb_last_t) = 1; + + /* + * We need to do the full-resync of the db, since the + * serial nos./timestamps are way out-of-whack + */ + kdb_fullresync_result_t + IPROP_FULL_RESYNC(void) = 2; + } = 1; +} = 100423; diff --git a/src/lib/kdb/iprop_xdr.c b/src/lib/kdb/iprop_xdr.c new file mode 100644 index 0000000000..a8b7685ffe --- /dev/null +++ b/src/lib/kdb/iprop_xdr.c @@ -0,0 +1,351 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "iprop.h" +#include "iprop.h" + +bool_t +xdr_int16_t (XDR *xdrs, int16_t *objp) +{ + register int32_t *buf; + + if (!xdr_short (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_uint16_t (XDR *xdrs, uint16_t *objp) +{ + register int32_t *buf; + + if (!xdr_u_short (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_int32_t (XDR *xdrs, int32_t *objp) +{ + register int32_t *buf; + + if (!xdr_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_uint32_t (XDR *xdrs, uint32_t *objp) +{ + register int32_t *buf; + + if (!xdr_u_int (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_utf8str_t (XDR *xdrs, utf8str_t *objp) +{ + register int32_t *buf; + + if (!xdr_bytes (xdrs, (char **)&objp->utf8str_t_val, (u_int *) &objp->utf8str_t_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_sno_t (XDR *xdrs, kdb_sno_t *objp) +{ + register int32_t *buf; + + if (!xdr_uint32_t (xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_time_t (XDR *xdrs, kdbe_time_t *objp) +{ + register int32_t *buf; + + if (!xdr_uint32_t (xdrs, &objp->seconds)) + return FALSE; + if (!xdr_uint32_t (xdrs, &objp->useconds)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_key_t (XDR *xdrs, kdbe_key_t *objp) +{ + register int32_t *buf; + + if (!xdr_int32_t (xdrs, &objp->k_ver)) + return FALSE; + if (!xdr_int32_t (xdrs, &objp->k_kvno)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->k_enctype.k_enctype_val, (u_int *) &objp->k_enctype.k_enctype_len, ~0, + sizeof (int32_t), (xdrproc_t) xdr_int32_t)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->k_contents.k_contents_val, (u_int *) &objp->k_contents.k_contents_len, ~0, + sizeof (utf8str_t), (xdrproc_t) xdr_utf8str_t)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_data_t (XDR *xdrs, kdbe_data_t *objp) +{ + register int32_t *buf; + + if (!xdr_int32_t (xdrs, &objp->k_magic)) + return FALSE; + if (!xdr_utf8str_t (xdrs, &objp->k_data)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_princ_t (XDR *xdrs, kdbe_princ_t *objp) +{ + register int32_t *buf; + + if (!xdr_utf8str_t (xdrs, &objp->k_realm)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->k_components.k_components_val, (u_int *) &objp->k_components.k_components_len, ~0, + sizeof (kdbe_data_t), (xdrproc_t) xdr_kdbe_data_t)) + return FALSE; + if (!xdr_int32_t (xdrs, &objp->k_nametype)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_tl_t (XDR *xdrs, kdbe_tl_t *objp) +{ + register int32_t *buf; + + if (!xdr_int16_t (xdrs, &objp->tl_type)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->tl_data.tl_data_val, (u_int *) &objp->tl_data.tl_data_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_pw_hist_t (XDR *xdrs, kdbe_pw_hist_t *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->kdbe_pw_hist_t_val, (u_int *) &objp->kdbe_pw_hist_t_len, ~0, + sizeof (kdbe_key_t), (xdrproc_t) xdr_kdbe_key_t)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_attr_type_t (XDR *xdrs, kdbe_attr_type_t *objp) +{ + register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdbe_val_t (XDR *xdrs, kdbe_val_t *objp) +{ + register int32_t *buf; + + if (!xdr_kdbe_attr_type_t (xdrs, &objp->av_type)) + return FALSE; + switch (objp->av_type) { + case AT_ATTRFLAGS: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_attrflags)) + return FALSE; + break; + case AT_MAX_LIFE: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_max_life)) + return FALSE; + break; + case AT_MAX_RENEW_LIFE: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_max_renew_life)) + return FALSE; + break; + case AT_EXP: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_exp)) + return FALSE; + break; + case AT_PW_EXP: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_pw_exp)) + return FALSE; + break; + case AT_LAST_SUCCESS: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_last_success)) + return FALSE; + break; + case AT_LAST_FAILED: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_last_failed)) + return FALSE; + break; + case AT_FAIL_AUTH_COUNT: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_fail_auth_count)) + return FALSE; + break; + case AT_PRINC: + if (!xdr_kdbe_princ_t (xdrs, &objp->kdbe_val_t_u.av_princ)) + return FALSE; + break; + case AT_KEYDATA: + if (!xdr_array (xdrs, (char **)&objp->kdbe_val_t_u.av_keydata.av_keydata_val, (u_int *) &objp->kdbe_val_t_u.av_keydata.av_keydata_len, ~0, + sizeof (kdbe_key_t), (xdrproc_t) xdr_kdbe_key_t)) + return FALSE; + break; + case AT_TL_DATA: + if (!xdr_array (xdrs, (char **)&objp->kdbe_val_t_u.av_tldata.av_tldata_val, (u_int *) &objp->kdbe_val_t_u.av_tldata.av_tldata_len, ~0, + sizeof (kdbe_tl_t), (xdrproc_t) xdr_kdbe_tl_t)) + return FALSE; + break; + case AT_LEN: + if (!xdr_int16_t (xdrs, &objp->kdbe_val_t_u.av_len)) + return FALSE; + break; + case AT_PW_LAST_CHANGE: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_pw_last_change)) + return FALSE; + break; + case AT_MOD_PRINC: + if (!xdr_kdbe_princ_t (xdrs, &objp->kdbe_val_t_u.av_mod_princ)) + return FALSE; + break; + case AT_MOD_TIME: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_mod_time)) + return FALSE; + break; + case AT_MOD_WHERE: + if (!xdr_utf8str_t (xdrs, &objp->kdbe_val_t_u.av_mod_where)) + return FALSE; + break; + case AT_PW_POLICY: + if (!xdr_utf8str_t (xdrs, &objp->kdbe_val_t_u.av_pw_policy)) + return FALSE; + break; + case AT_PW_POLICY_SWITCH: + if (!xdr_bool (xdrs, &objp->kdbe_val_t_u.av_pw_policy_switch)) + return FALSE; + break; + case AT_PW_HIST_KVNO: + if (!xdr_uint32_t (xdrs, &objp->kdbe_val_t_u.av_pw_hist_kvno)) + return FALSE; + break; + case AT_PW_HIST: + if (!xdr_array (xdrs, (char **)&objp->kdbe_val_t_u.av_pw_hist.av_pw_hist_val, (u_int *) &objp->kdbe_val_t_u.av_pw_hist.av_pw_hist_len, ~0, + sizeof (kdbe_pw_hist_t), (xdrproc_t) xdr_kdbe_pw_hist_t)) + return FALSE; + break; + default: + if (!xdr_bytes (xdrs, (char **)&objp->kdbe_val_t_u.av_extension.av_extension_val, (u_int *) &objp->kdbe_val_t_u.av_extension.av_extension_len, ~0)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_kdbe_t (XDR *xdrs, kdbe_t *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->kdbe_t_val, (u_int *) &objp->kdbe_t_len, ~0, + sizeof (kdbe_val_t), (xdrproc_t) xdr_kdbe_val_t)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_incr_update_t (XDR *xdrs, kdb_incr_update_t *objp) +{ + register int32_t *buf; + + if (!xdr_utf8str_t (xdrs, &objp->kdb_princ_name)) + return FALSE; + if (!xdr_kdb_sno_t (xdrs, &objp->kdb_entry_sno)) + return FALSE; + if (!xdr_kdbe_time_t (xdrs, &objp->kdb_time)) + return FALSE; + if (!xdr_kdbe_t (xdrs, &objp->kdb_update)) + return FALSE; + if (!xdr_bool (xdrs, &objp->kdb_deleted)) + return FALSE; + if (!xdr_bool (xdrs, &objp->kdb_commit)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val, (u_int *) &objp->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len, ~0, + sizeof (utf8str_t), (xdrproc_t) xdr_utf8str_t)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->kdb_futures.kdb_futures_val, (u_int *) &objp->kdb_futures.kdb_futures_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_ulog_t (XDR *xdrs, kdb_ulog_t *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->kdb_ulog_t_val, (u_int *) &objp->kdb_ulog_t_len, ~0, + sizeof (kdb_incr_update_t), (xdrproc_t) xdr_kdb_incr_update_t)) + return FALSE; + return TRUE; +} + +bool_t +xdr_update_status_t (XDR *xdrs, update_status_t *objp) +{ + register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_last_t (XDR *xdrs, kdb_last_t *objp) +{ + register int32_t *buf; + + if (!xdr_kdb_sno_t (xdrs, &objp->last_sno)) + return FALSE; + if (!xdr_kdbe_time_t (xdrs, &objp->last_time)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_incr_result_t (XDR *xdrs, kdb_incr_result_t *objp) +{ + register int32_t *buf; + + if (!xdr_kdb_last_t (xdrs, &objp->lastentry)) + return FALSE; + if (!xdr_kdb_ulog_t (xdrs, &objp->updates)) + return FALSE; + if (!xdr_update_status_t (xdrs, &objp->ret)) + return FALSE; + return TRUE; +} + +bool_t +xdr_kdb_fullresync_result_t (XDR *xdrs, kdb_fullresync_result_t *objp) +{ + register int32_t *buf; + + if (!xdr_kdb_last_t (xdrs, &objp->lastentry)) + return FALSE; + if (!xdr_update_status_t (xdrs, &objp->ret)) + return FALSE; + return TRUE; +} diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index bdade99047..d782d0f413 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -37,6 +37,7 @@ #include <osconf.h> #include "kdb5.h" #include <assert.h> +#include "kdb_log.h" /* Currently DB2 policy related errors are exported from DAL. But other databases should set_err function to return string. */ @@ -935,29 +936,35 @@ krb5_db_free_principal(krb5_context kcontext, krb5_db_entry * entry, int count) return status; } -krb5_error_code -krb5_db_put_principal(krb5_context kcontext, - krb5_db_entry * entries, int *nentries) +static void +free_db_args(krb5_context kcontext, char **db_args) { - krb5_error_code status = 0; - kdb5_dal_handle *dal_handle; - char **db_args = NULL; - krb5_tl_data *prev, *curr, *next; - int db_args_size = 0; - - if (kcontext->dal_handle == NULL) { - status = kdb_setup_lib_handle(kcontext); - if (status) { - goto clean_n_exit; - } + int i; + if (db_args) { + /* XXX Is this right? Or are we borrowing storage from + the caller? */ + for (i = 0; db_args[i]; i++) + krb5_db_free(kcontext, db_args[i]); + free(db_args); } +} + +static krb5_error_code +extract_db_args_from_tl_data(krb5_context kcontext, + krb5_tl_data **start, krb5_int16 *count, + char ***db_argsp) +{ + char **db_args = NULL; + int db_args_size = 0; + krb5_tl_data *prev, *curr, *next; + krb5_error_code status; /* Giving db_args as part of tl data causes db2 to store the tl_data as such. To prevent this, tl_data is collated and passed as a separate argument. Currently supports only one principal, but passing it as a separate argument makes it difficult for kadmin remote to pass arguments to server. */ - prev = NULL, curr = entries->tl_data; + prev = NULL, curr = *start; while (curr) { if (curr->tl_data_type == KRB5_TL_DB_ARGS) { char **t; @@ -985,11 +992,11 @@ krb5_db_put_principal(krb5_context kcontext, next = curr->tl_data_next; if (prev == NULL) { /* current node is the first in the linked list. remove it */ - entries->tl_data = curr->tl_data_next; + *start = curr->tl_data_next; } else { prev->tl_data_next = curr->tl_data_next; } - entries->n_tl_data--; + (*count)--; krb5_db_free(kcontext, curr); /* previous does not change */ @@ -999,6 +1006,67 @@ krb5_db_put_principal(krb5_context kcontext, curr = curr->tl_data_next; } } + status = 0; +clean_n_exit: + if (status != 0) { + free_db_args(kcontext, db_args); + db_args = NULL; + } + *db_argsp = db_args; + return status; +} + +krb5_error_code +krb5int_put_principal_no_log(krb5_context kcontext, + krb5_db_entry *entries, int *nentries) +{ + kdb5_dal_handle *dal_handle; + krb5_error_code status; + char **db_args; + + status = extract_db_args_from_tl_data(kcontext, &entries->tl_data, + &entries->n_tl_data, + &db_args); + if (status) + return status; + assert (kcontext->dal_handle != NULL); /* XXX */ + dal_handle = kcontext->dal_handle; + /* XXX Locking? */ + status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries, + nentries, + db_args); + get_errmsg(kcontext, status); + free_db_args(kcontext, db_args); + return status; +} + +krb5_error_code +krb5_db_put_principal(krb5_context kcontext, + krb5_db_entry * entries, int *nentries) +{ + krb5_error_code status = 0; + kdb5_dal_handle *dal_handle; + char **db_args = NULL; + kdb_incr_update_t *upd, *fupd; + char *princ_name = NULL; + kdb_log_context *log_ctx; + int i; + int ulog_locked = 0; + + log_ctx = kcontext->kdblog_context; + + if (kcontext->dal_handle == NULL) { + status = kdb_setup_lib_handle(kcontext); + if (status) { + goto clean_n_exit; + } + } + + status = extract_db_args_from_tl_data(kcontext, &entries->tl_data, + &entries->n_tl_data, + &db_args); + if (status) + goto clean_n_exit; dal_handle = kcontext->dal_handle; status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); @@ -1006,23 +1074,89 @@ krb5_db_put_principal(krb5_context kcontext, goto clean_n_exit; } + /* + * We need the lock since ulog_conv_2logentry() does a get + */ + if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) { + if (!(upd = (kdb_incr_update_t *) + malloc(sizeof (kdb_incr_update_t)* *nentries))) { + status = errno; + goto err_lock; + } + fupd = upd; + + (void) memset(upd, 0, sizeof(kdb_incr_update_t)* *nentries); + + if ((status = ulog_conv_2logentry(kcontext, entries, upd, *nentries))) { + goto err_lock; + } + } + + status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE); + if (status != 0) + goto err_lock; + ulog_locked = 1; + + for (i = 0; i < *nentries; i++) { + /* + * We'll be sharing the same locks as db for logging + */ + if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) { + if ((status = krb5_unparse_name(kcontext, entries->princ, + &princ_name))) + goto err_lock; + + upd->kdb_princ_name.utf8str_t_val = princ_name; + upd->kdb_princ_name.utf8str_t_len = strlen(princ_name); + + if (status = ulog_add_update(kcontext, upd)) + goto err_lock; + } + upd++; + } + status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries, nentries, db_args); get_errmsg(kcontext, status); + if (status == 0 && log_ctx && log_ctx->iproprole == IPROP_MASTER) { + upd = fupd; + for (i = 0; i < *nentries; i++) { + (void) ulog_finish_update(kcontext, upd); + upd++; + } + } +err_lock: + if (ulog_locked) + ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK); + kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); clean_n_exit: - while (db_args_size) { - if (db_args[db_args_size - 1]) - krb5_db_free(kcontext, db_args[db_args_size - 1]); + free_db_args(kcontext, db_args); - db_args_size--; - } + if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) + ulog_free_entries(fupd, *nentries); - if (db_args) - free(db_args); + return status; +} + +krb5_error_code +krb5int_delete_principal_no_log(krb5_context kcontext, + krb5_principal search_for, + int *nentries) +{ + kdb5_dal_handle *dal_handle; + krb5_error_code status; + + assert (kcontext->dal_handle != NULL); /* XXX */ + dal_handle = kcontext->dal_handle; + /* XXX Locking? */ + status = dal_handle->lib_handle->vftabl.db_delete_principal(kcontext, + search_for, + nentries); + get_errmsg(kcontext, status); return status; } @@ -1032,6 +1166,11 @@ krb5_db_delete_principal(krb5_context kcontext, { krb5_error_code status = 0; kdb5_dal_handle *dal_handle; + kdb_incr_update_t upd; + char *princ_name = NULL; + kdb_log_context *log_ctx; + + log_ctx = kcontext->kdblog_context; if (kcontext->dal_handle == NULL) { status = kdb_setup_lib_handle(kcontext); @@ -1046,11 +1185,50 @@ krb5_db_delete_principal(krb5_context kcontext, goto clean_n_exit; } - status = - dal_handle->lib_handle->vftabl.db_delete_principal(kcontext, - search_for, - nentries); + status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE); + if (status) { + kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); + return status; + } + + /* + * We'll be sharing the same locks as db for logging + */ + if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) { + if ((status = krb5_unparse_name(kcontext, search_for, &princ_name))) { + ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK); + (void) kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); + return status; + } + + (void) memset(&upd, 0, sizeof (kdb_incr_update_t)); + + upd.kdb_princ_name.utf8str_t_val = princ_name; + upd.kdb_princ_name.utf8str_t_len = strlen(princ_name); + + if ((status = ulog_delete_update(kcontext, &upd)) != 0) { + ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK); + free(princ_name); + (void) kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); + return status; + } + + free(princ_name); + } + + status = dal_handle->lib_handle->vftabl.db_delete_principal(kcontext, + search_for, + nentries); get_errmsg(kcontext, status); + + /* + * We need to commit our update upon success + */ + if (!status) + if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) + (void) ulog_finish_update(kcontext, &upd); + + ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK); kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); clean_n_exit: diff --git a/src/lib/kdb/kdb_convert.c b/src/lib/kdb/kdb_convert.c new file mode 100644 index 0000000000..61b2b97471 --- /dev/null +++ b/src/lib/kdb/kdb_convert.c @@ -0,0 +1,1017 @@ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)kdb_convert.c 1.3 05/01/05 SMI" */ + +/* + * This file contains api's for conversion of the kdb_incr_update_t + * struct(s) into krb5_db_entry struct(s) and vice-versa. + */ +#include <sys/types.h> +#include <com_err.h> +#include <locale.h> +#include <errno.h> +#include <iprop_hdr.h> +#include "iprop.h" +#include <k5-int.h> +#include <kdb.h> + +/* BEGIN CSTYLED */ +#define ULOG_ENTRY_TYPE(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i] + +#define ULOG_ENTRY(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u + +#define ULOG_ENTRY_KEYVAL(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_keydata.av_keydata_val[j] + +#define ULOG_ENTRY_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_princ.k_components.k_components_val[j] + +#define ULOG_ENTRY_MOD_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_mod_princ.k_components.k_components_val[j] +/* END CSTYLED */ + +typedef enum { + REG_PRINC = 0, + MOD_PRINC = 1 +} princ_type; + + +/* + * This routine tracks the krb5_db_entry fields that have been modified + * (by comparing it to the db_entry currently present in principal.db) + * in the update. + */ +static void +find_changed_attrs(krb5_db_entry *current, krb5_db_entry *new, + kdbe_attr_type_t *attrs, int *nattrs) +{ + int i = 0, j = 0; + + krb5_tl_data *first, *second; + + if (current->attributes != new->attributes) + attrs[i++] = AT_ATTRFLAGS; + + if (current->max_life != new->max_life) + attrs[i++] = AT_MAX_LIFE; + + if (current->max_renewable_life != new->max_renewable_life) + attrs[i++] = AT_MAX_RENEW_LIFE; + + if (current->expiration != new->expiration) + attrs[i++] = AT_EXP; + + if (current->pw_expiration != new->pw_expiration) + attrs[i++] = AT_PW_EXP; + + if (current->last_success != new->last_success) + attrs[i++] = AT_LAST_SUCCESS; + + if (current->last_failed != new->last_failed) + attrs[i++] = AT_LAST_FAILED; + + if (current->fail_auth_count != new->fail_auth_count) + attrs[i++] = AT_FAIL_AUTH_COUNT; + + if ((current->princ->type == new->princ->type) && + (current->princ->length == new->princ->length)) { + if ((current->princ->realm.length == + new->princ->realm.length) && + strncmp(current->princ->realm.data, + new->princ->realm.data, + current->princ->realm.length)) { + for (j = 0; j < current->princ->length; j++) { + if ((current->princ->data[j].data != NULL) && + (strncmp(current->princ->data[j].data, + new->princ->data[j].data, + current->princ->data[j].length))) { + attrs[i++] = AT_PRINC; + break; + } + } + } else { + attrs[i++] = AT_PRINC; + } + } else { + attrs[i++] = AT_PRINC; + } + + if (current->n_key_data == new->n_key_data) { + /* Assuming key ordering is the same in new & current */ + for (j = 0; j < new->n_key_data; j++) { + if (current->key_data[j].key_data_kvno != + new->key_data[j].key_data_kvno) { + attrs[i++] = AT_KEYDATA; + break; + } + } + } else { + attrs[i++] = AT_KEYDATA; + } + + if (current->n_tl_data == new->n_tl_data) { + /* Assuming we preserve the TL_DATA ordering between updates */ + for (first = current->tl_data, second = new->tl_data; + first; first = first->tl_data_next, + second = second->tl_data_next) { + if ((first->tl_data_length == second->tl_data_length) && + (first->tl_data_type == second->tl_data_type)) { + if ((memcmp((char *)first->tl_data_contents, + (char *)second->tl_data_contents, + first->tl_data_length)) != 0) { + attrs[i++] = AT_TL_DATA; + break; + } + } else { + attrs[i++] = AT_TL_DATA; + break; + } + } + + } else { + attrs[i++] = AT_TL_DATA; + } + + if (current->len != new->len) + attrs[i++] = AT_LEN; + /* + * Store the no. of (possibly :)) changed attributes + */ + *nattrs = i; +} + + +/* + */ +static int +data_to_utf8str(utf8str_t *u, krb5_data d) +{ + u->utf8str_t_len = d.length; + if (d.data) { + /* XXX Is the data always a nul-terminated string? */ + u->utf8str_t_val = strdup(d.data); + if (u->utf8str_t_val == NULL) + return -1; + } else + u->utf8str_t_val = NULL; + return 0; +} + +/* + * Converts the krb5_principal struct from db2 to ulog format. + */ +krb5_error_code +conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd, + int cnt, princ_type tp) +{ + int i = 0; + kdbe_princ_t *p; + kdbe_data_t *components; + + if ((upd == NULL) || !princ) + return (KRB5KRB_ERR_GENERIC); + + switch (tp) { + case REG_PRINC: + case MOD_PRINC: + p = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */ + p->k_nametype = (int32_t)princ->type; + + if (data_to_utf8str(&p->k_realm, princ->realm) < 0) { + return ENOMEM; + } + + p->k_components.k_components_len = princ->length; + + p->k_components.k_components_val = components + = malloc(princ->length * sizeof (kdbe_data_t)); + if (p->k_components.k_components_val == NULL) { + free(p->k_realm.utf8str_t_val); + p->k_realm.utf8str_t_val = NULL; + return (ENOMEM); + } + + memset(components, 0, princ->length * sizeof(kdbe_data_t)); + for (i = 0; i < princ->length; i++) + components[i].k_data.utf8str_t_val = NULL; + for (i = 0; i < princ->length; i++) { + components[i].k_magic = princ->data[i].magic; + if (data_to_utf8str(&components[i].k_data, princ->data[i]) < 0) { + int j; + for (j = 0; j < i; j++) { + free(components[j].k_data.utf8str_t_val); + components[j].k_data.utf8str_t_val = NULL; + } + free(components); + p->k_components.k_components_val = NULL; + free(p->k_realm.utf8str_t_val); + p->k_realm.utf8str_t_val = NULL; + return ENOMEM; + } + } + break; + + default: + break; + } + return (0); +} + +/* + * Copies a UTF-8 string from ulog to a krb5_data object, which may + * already have allocated storage associated with it. + * + * Maybe a return value should indicate success/failure? + */ +static void +replace_with_utf8str(krb5_data *d, utf8str_t u) +{ + d->length = u.utf8str_t_len; + /* XXX Memory leak: old d->data if realloc failed. */ + /* XXX Overflow check? d->length + 1. */ + d->data = realloc(d->data, d->length + 1); + if (d->data == NULL) + return; + if (u.utf8str_t_val) /* May be null if length = 0. */ + strncpy(d->data, u.utf8str_t_val, d->length + 1); + d->data[d->length] = 0; +} + +/* + * Converts the krb5_principal struct from ulog to db2 format. + */ +krb5_error_code +conv_princ_2db(krb5_context context, krb5_principal *dbprinc, + kdb_incr_update_t *upd, + int cnt, princ_type tp, + int princ_exists) +{ + int i; + krb5_principal princ; + kdbe_princ_t *kdbe_princ; + kdbe_data_t *components; + + if (upd == NULL) + return (KRB5KRB_ERR_GENERIC); + + if (princ_exists == 0) { + princ = NULL; + princ = (krb5_principal)malloc(sizeof (krb5_principal_data)); + if (princ == NULL) { + return (ENOMEM); + } + } else { + princ = *dbprinc; + } + + switch (tp) { + case REG_PRINC: + case MOD_PRINC: + kdbe_princ = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */ + components = kdbe_princ->k_components.k_components_val; + + princ->type = (krb5_int32) + kdbe_princ->k_nametype; + if (princ_exists == 0) + princ->realm.data = NULL; + replace_with_utf8str(&princ->realm, kdbe_princ->k_realm); + if (princ->realm.data == NULL) + goto error; + + /* Free up old entries we're about to release. */ + if (princ_exists) { + for (i = kdbe_princ->k_components.k_components_len; i < princ->length; i++) { + free(princ->data[i].data); + princ->data[i].data = NULL; + } + } else + princ->data = NULL; + princ->data = (krb5_data *)realloc(princ->data, + (princ->length * sizeof (krb5_data))); + if (princ->data == NULL) + /* XXX Memory leak: old storage not freed. */ + goto error; + /* Initialize pointers in added component slots. */ + for (i = princ->length; i < kdbe_princ->k_components.k_components_len; i++) { + princ->data[i].data = NULL; + } + princ->length = (krb5_int32)kdbe_princ->k_components.k_components_len; + + for (i = 0; i < princ->length; i++) { + princ->data[i].magic = + components[i].k_magic; + if (princ_exists == 0) + princ->data[i].data = NULL; + replace_with_utf8str(&princ->data[i], + components[i].k_data); + if (princ->data[i].data == NULL) + goto error; + } + break; + + default: + break; + } + + *dbprinc = princ; + return (0); +error: + krb5_free_principal(context, princ); + return (ENOMEM); +} + + +/* + * This routine converts one or more krb5 db2 records into update + * log (ulog) entry format. Space for the update log entries should + * be allocated prior to invocation of this routine. + */ +krb5_error_code +ulog_conv_2logentry(krb5_context context, krb5_db_entry *entries, + kdb_incr_update_t *updates, + int nentries) +{ + int i, j, k, cnt, final, nattrs, tmpint, nprincs; + unsigned int more; + krb5_principal tmpprinc; + krb5_tl_data *newtl; + krb5_db_entry curr; + krb5_error_code ret; + kdbe_attr_type_t *attr_types; + kdb_incr_update_t *upd; + krb5_db_entry *ent; + int kadm_data_yes; + + if ((updates == NULL) || (entries == NULL)) + return (KRB5KRB_ERR_GENERIC); + + upd = updates; + ent = entries; + + for (k = 0; k < nentries; k++) { + nprincs = nattrs = tmpint = 0; + final = -1; + kadm_data_yes = 0; + attr_types = NULL; + + if ((upd->kdb_update.kdbe_t_val = (kdbe_val_t *) + malloc(MAXENTRY_SIZE)) == NULL) { + return (ENOMEM); + } + + /* + * Find out which attrs have been modified + */ + if ((attr_types = (kdbe_attr_type_t *)malloc( + sizeof (kdbe_attr_type_t) * MAXATTRS_SIZE)) + == NULL) { + return (ENOMEM); + } + + if ((ret = krb5_db_get_principal(context, ent->princ, &curr, + &nprincs, &more))) + return (ret); + + if (nprincs == 0) { + /* + * This is a new entry to the database, hence will + * include all the attribute-value pairs + * + * We leave out the TL_DATA types which we model as + * attrs in kdbe_attr_type_t, since listing AT_TL_DATA + * encompasses these other types-turned-attributes + * + * So, we do *NOT* consider AT_MOD_PRINC, AT_MOD_TIME, + * AT_MOD_WHERE, AT_PW_LAST_CHANGE, AT_PW_POLICY, + * AT_PW_POLICY_SWITCH, AT_PW_HIST_KVNO and AT_PW_HIST, + * totalling 8 attrs. + */ + while (nattrs < MAXATTRS_SIZE - 8) { + attr_types[nattrs] = nattrs; + nattrs++; + } + } else { + find_changed_attrs(&curr, ent, attr_types, &nattrs); + + krb5_db_free_principal(context, &curr, nprincs); + } + + for (i = 0; i < nattrs; i++) { + switch (attr_types[i]) { + case AT_ATTRFLAGS: + if (ent->attributes >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_ATTRFLAGS; + ULOG_ENTRY(upd, final).av_attrflags = + (uint32_t)ent->attributes; + } + break; + + case AT_MAX_LIFE: + if (ent->max_life >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_MAX_LIFE; + ULOG_ENTRY(upd, final).av_max_life = + (uint32_t)ent->max_life; + } + break; + + case AT_MAX_RENEW_LIFE: + if (ent->max_renewable_life >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_MAX_RENEW_LIFE; + ULOG_ENTRY(upd, + final).av_max_renew_life = + (uint32_t)ent->max_renewable_life; + } + break; + + case AT_EXP: + if (ent->expiration >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_EXP; + ULOG_ENTRY(upd, final).av_exp = + (uint32_t)ent->expiration; + } + break; + + case AT_PW_EXP: + if (ent->pw_expiration >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_PW_EXP; + ULOG_ENTRY(upd, final).av_pw_exp = + (uint32_t)ent->pw_expiration; + } + break; + + case AT_LAST_SUCCESS: + if (ent->last_success >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_LAST_SUCCESS; + ULOG_ENTRY(upd, + final).av_last_success = + (uint32_t)ent->last_success; + } + break; + + case AT_LAST_FAILED: + if (ent->last_failed >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_LAST_FAILED; + ULOG_ENTRY(upd, + final).av_last_failed = + (uint32_t)ent->last_failed; + } + break; + + case AT_FAIL_AUTH_COUNT: + if (ent->fail_auth_count >= (krb5_kvno)0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_FAIL_AUTH_COUNT; + ULOG_ENTRY(upd, + final).av_fail_auth_count = + (uint32_t)ent->fail_auth_count; + } + break; + + case AT_PRINC: + if (ent->princ->length > 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_PRINC; + if ((ret = conv_princ_2ulog(ent->princ, + upd, final, REG_PRINC))) + return (ret); + } + break; + + case AT_KEYDATA: +/* BEGIN CSTYLED */ + if (ent->n_key_data >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_KEYDATA; + ULOG_ENTRY(upd, final).av_keydata.av_keydata_len = ent->n_key_data; + + ULOG_ENTRY(upd, final).av_keydata.av_keydata_val = malloc(ent->n_key_data * sizeof (kdbe_key_t)); + if (ULOG_ENTRY(upd, final).av_keydata.av_keydata_val == NULL) + return (ENOMEM); + + for (j = 0; j < ent->n_key_data; j++) { + ULOG_ENTRY_KEYVAL(upd, final, j).k_ver = ent->key_data[j].key_data_ver; + ULOG_ENTRY_KEYVAL(upd, final, j).k_kvno = ent->key_data[j].key_data_kvno; + ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_len = ent->key_data[j].key_data_ver; + ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_len = ent->key_data[j].key_data_ver; + + ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val = malloc(ent->key_data[j].key_data_ver * sizeof(int32_t)); + if (ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val == NULL) + return (ENOMEM); + + ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val = malloc(ent->key_data[j].key_data_ver * sizeof(utf8str_t)); + if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val == NULL) + return (ENOMEM); + + for (cnt = 0; cnt < ent->key_data[j].key_data_ver; cnt++) { + ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val[cnt] = ent->key_data[j].key_data_type[cnt]; + ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_len = ent->key_data[j].key_data_length[cnt]; + ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val = malloc(ent->key_data[j].key_data_length[cnt] * sizeof (char)); + if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val == NULL) + return (ENOMEM); + (void) memcpy(ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val, ent->key_data[j].key_data_contents[cnt], ent->key_data[j].key_data_length[cnt]); + } + } + } + break; + + case AT_TL_DATA: + ret = krb5_dbe_lookup_last_pwd_change(context, + ent, &tmpint); + if (ret == 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_PW_LAST_CHANGE; + ULOG_ENTRY(upd, final).av_pw_last_change = tmpint; + } + tmpint = 0; + + if(!(ret = krb5_dbe_lookup_mod_princ_data( + context, ent, &tmpint, &tmpprinc))) { + + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_MOD_PRINC; + + ret = conv_princ_2ulog(tmpprinc, + upd, final, MOD_PRINC); + krb5_free_principal(context, tmpprinc); + if (ret) + return (ret); + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_MOD_TIME; + ULOG_ENTRY(upd, final).av_mod_time = + tmpint; + } + + newtl = ent->tl_data; + while (newtl) { + switch (newtl->tl_data_type) { + case KRB5_TL_LAST_PWD_CHANGE: + case KRB5_TL_MOD_PRINC: + break; + + case KRB5_TL_KADM_DATA: + default: + if (kadm_data_yes == 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = AT_TL_DATA; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_len = 0; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_val = malloc(ent->n_tl_data * sizeof(kdbe_tl_t)); + + if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val == NULL) + return (ENOMEM); + kadm_data_yes = 1; + } + + tmpint = ULOG_ENTRY(upd, final).av_tldata.av_tldata_len; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_len++; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_type = newtl->tl_data_type; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_len = newtl->tl_data_length; + ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val = malloc(newtl->tl_data_length * sizeof (char)); + if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val == NULL) + return (ENOMEM); + (void) memcpy(ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val, newtl->tl_data_contents, newtl->tl_data_length); + break; + } + newtl = newtl->tl_data_next; + } + break; +/* END CSTYLED */ + + case AT_LEN: + if (ent->len >= 0) { + ULOG_ENTRY_TYPE(upd, ++final).av_type = + AT_LEN; + ULOG_ENTRY(upd, final).av_len = + (int16_t)ent->len; + } + break; + + default: + break; + } + + } + + free(attr_types); + + /* + * Update len field in kdb_update + */ + upd->kdb_update.kdbe_t_len = ++final; + + /* + * Bump up to next struct + */ + upd++; + ent++; + } + return (0); +} + +/* + * This routine converts one or more update log (ulog) entries into + * kerberos db2 records. Required memory should be allocated + * for the db2 records (pointed to by krb5_db_entry *ent), prior + * to calling this routine. + */ +krb5_error_code +ulog_conv_2dbentry(krb5_context context, krb5_db_entry *entries, + kdb_incr_update_t *updates, + int nentries) +{ + int i, j, k, cnt, mod_time = 0, nattrs, nprincs; + krb5_principal mod_princ = NULL; + krb5_principal dbprinc; + char *dbprincstr = NULL; + + krb5_db_entry *ent; + kdb_incr_update_t *upd; + + krb5_tl_data *newtl = NULL; + krb5_error_code ret; + unsigned int more; + unsigned int prev_n_keys = 0; + + if ((updates == NULL) || (entries == NULL)) + return (KRB5KRB_ERR_GENERIC); + + ent = entries; + upd = updates; + + for (k = 0; k < nentries; k++) { + cnt = nprincs = 0; + + /* + * If the ulog entry represents a DELETE update, + * just skip to the next entry. + */ + if (upd->kdb_deleted == TRUE) + goto next; + + /* + * Store the no. of changed attributes in nattrs + */ + nattrs = upd->kdb_update.kdbe_t_len; + + dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len + 1) + * sizeof (char)); + if (dbprincstr == NULL) + return (ENOMEM); + strncpy(dbprincstr, (char *)upd->kdb_princ_name.utf8str_t_val, + (upd->kdb_princ_name.utf8str_t_len + 1)); + dbprincstr[upd->kdb_princ_name.utf8str_t_len] = 0; + + ret = krb5_parse_name(context, dbprincstr, &dbprinc); + free(dbprincstr); + if (ret) + return (ret); + + ret = krb5_db_get_principal(context, dbprinc, ent, &nprincs, + &more); + krb5_free_principal(context, dbprinc); + if (ret) + return (ret); + + /* + * Set ent->n_tl_data = 0 initially, if this is an ADD update + */ + if (nprincs == 0) + ent->n_tl_data = 0; + + for (i = 0; i < nattrs; i++) { + switch (ULOG_ENTRY_TYPE(upd, i).av_type) { + case AT_ATTRFLAGS: + ent->attributes = (krb5_flags) + ULOG_ENTRY(upd, i).av_attrflags; + break; + + case AT_MAX_LIFE: + ent->max_life = (krb5_deltat) + ULOG_ENTRY(upd, i).av_max_life; + break; + + case AT_MAX_RENEW_LIFE: + ent->max_renewable_life = (krb5_deltat) + ULOG_ENTRY(upd, i).av_max_renew_life; + break; + + case AT_EXP: + ent->expiration = (krb5_timestamp) + ULOG_ENTRY(upd, i).av_exp; + break; + + case AT_PW_EXP: + ent->pw_expiration = (krb5_timestamp) + ULOG_ENTRY(upd, i).av_pw_exp; + break; + + case AT_LAST_SUCCESS: + ent->last_success = (krb5_timestamp) + ULOG_ENTRY(upd, i).av_last_success; + break; + + case AT_LAST_FAILED: + ent->last_failed = (krb5_timestamp) + ULOG_ENTRY(upd, i).av_last_failed; + break; + + case AT_FAIL_AUTH_COUNT: + ent->fail_auth_count = (krb5_kvno) + ULOG_ENTRY(upd, i).av_fail_auth_count; + break; + + case AT_PRINC: + if ((ret = conv_princ_2db(context, + &(ent->princ), upd, + i, REG_PRINC, nprincs))) + return (ret); + break; + + case AT_KEYDATA: + if (nprincs != 0) + prev_n_keys = ent->n_key_data; + ent->n_key_data = (krb5_int16)ULOG_ENTRY(upd, + i).av_keydata.av_keydata_len; + if (nprincs == 0) + ent->key_data = NULL; + + ent->key_data = (krb5_key_data *)realloc( + ent->key_data, + (ent->n_key_data * + sizeof (krb5_key_data))); + /* XXX Memory leak: Old key data in + records eliminated by resizing to + smaller size. */ + if (ent->key_data == NULL) + /* XXX Memory leak: old storage. */ + return (ENOMEM); + +/* BEGIN CSTYLED */ + for (j = 0; j < ent->n_key_data; j++) { + ent->key_data[j].key_data_ver = (krb5_int16)ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; + ent->key_data[j].key_data_kvno = (krb5_int16)ULOG_ENTRY_KEYVAL(upd, i, j).k_kvno; + + for (cnt = 0; cnt < ent->key_data[j].key_data_ver; cnt++) { + ent->key_data[j].key_data_type[cnt] = (krb5_int16)ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val[cnt]; + ent->key_data[j].key_data_length[cnt] = (krb5_int16)ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[cnt].utf8str_t_len; + if ((nprincs == 0) || (j >= prev_n_keys)) + ent->key_data[j].key_data_contents[cnt] = NULL; + + ent->key_data[j].key_data_contents[cnt] = (krb5_octet *)realloc(ent->key_data[j].key_data_contents[cnt], ent->key_data[j].key_data_length[cnt]); + if (ent->key_data[j].key_data_contents[cnt] == NULL) + /* XXX Memory leak: old storage. */ + return (ENOMEM); + + (void) memset(ent->key_data[j].key_data_contents[cnt], 0, (ent->key_data[j].key_data_length[cnt] * sizeof (krb5_octet))); + (void) memcpy(ent->key_data[j].key_data_contents[cnt], ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[cnt].utf8str_t_val, ent->key_data[j].key_data_length[cnt]); + } + } + break; + + case AT_TL_DATA: + cnt = ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; + newtl = malloc(cnt * sizeof (krb5_tl_data)); + (void) memset(newtl, 0, (cnt * sizeof (krb5_tl_data))); + if (newtl == NULL) + return (ENOMEM); + + for (j = 0; j < cnt; j++){ + newtl[j].tl_data_type = (krb5_int16)ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_type; + newtl[j].tl_data_length = (krb5_int16)ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_len; + newtl[j].tl_data_contents = NULL; + newtl[j].tl_data_contents = malloc(newtl[j].tl_data_length * sizeof (krb5_octet)); + if (newtl[j].tl_data_contents == NULL) + /* XXX Memory leak: newtl + and previously + allocated elements. */ + return (ENOMEM); + + (void) memset(newtl[j].tl_data_contents, 0, (newtl[j].tl_data_length * sizeof (krb5_octet))); + (void) memcpy(newtl[j].tl_data_contents, ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val, newtl[j].tl_data_length); + newtl[j].tl_data_next = NULL; + if (j > 0) + newtl[j - 1].tl_data_next = + &newtl[j]; + } + + if ((ret = krb5_dbe_update_tl_data(context, + ent, newtl))) + return (ret); + for (j = 0; j < cnt; j++) + if (newtl[j].tl_data_contents) { + free(newtl[j].tl_data_contents); + newtl[j].tl_data_contents = NULL; + } + if (newtl) { + free(newtl); + newtl = NULL; + } + break; +/* END CSTYLED */ + + case AT_PW_LAST_CHANGE: + if ((ret = krb5_dbe_update_last_pwd_change( + context, ent, + ULOG_ENTRY(upd, i).av_pw_last_change))) + return (ret); + break; + + case AT_MOD_PRINC: + if ((ret = conv_princ_2db(context, + &mod_princ, upd, + i, MOD_PRINC, 0))) + return (ret); + break; + + case AT_MOD_TIME: + mod_time = ULOG_ENTRY(upd, i).av_mod_time; + break; + + case AT_LEN: + ent->len = (krb5_int16) + ULOG_ENTRY(upd, i).av_len; + break; + + default: + break; + } + + } + + /* + * process mod_princ_data request + */ + if (mod_time && mod_princ) { + ret = krb5_dbe_update_mod_princ_data(context, ent, + mod_time, mod_princ); + krb5_free_principal(context, mod_princ); + if (ret) + return (ret); + } + + next: + /* + * Bump up to next struct + */ + upd++; + ent++; + } + return (0); +} + + + +/* + * This routine frees up memory associated with the bunched ulog entries. + */ +void +ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates) +{ + + kdb_incr_update_t *upd; + int i, j, k, cnt; + + if (updates == NULL) + return; + + upd = updates; + + /* + * Loop thru each ulog entry + */ + for (cnt = 0; cnt < no_of_updates; cnt++) { + + /* + * ulog entry - kdb_princ_name + */ + free(upd->kdb_princ_name.utf8str_t_val); + +/* BEGIN CSTYLED */ + + /* + * ulog entry - kdb_kdcs_seen_by + */ + if (upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val) { + for (i = 0; i < upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len; i++) + free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val[i].utf8str_t_val); + free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val); + } + + /* + * ulog entry - kdb_futures + */ + free(upd->kdb_futures.kdb_futures_val); + + /* + * ulog entry - kdb_update + */ + if (upd->kdb_update.kdbe_t_val) { + /* + * Loop thru all the attributes and free up stuff + */ + for (i = 0; i < upd->kdb_update.kdbe_t_len; i++) { + + /* + * Free av_key_data + */ + if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_KEYDATA) && ULOG_ENTRY(upd, i).av_keydata.av_keydata_val) { + + for (j = 0; j < ULOG_ENTRY(upd, i).av_keydata.av_keydata_len; j++) { + free(ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val); + if (ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val) { + for (k = 0; k < ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; k++) { + free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[k].utf8str_t_val); + } + free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val); + } + } + free(ULOG_ENTRY(upd, i).av_keydata.av_keydata_val); + } + + + /* + * Free av_tl_data + */ + if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_TL_DATA) && ULOG_ENTRY(upd, i).av_tldata.av_tldata_val) { + for (j = 0; j < ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; j++) { + free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val); + } + free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val); + } + + /* + * Free av_princ + */ + if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_PRINC) { + free(ULOG_ENTRY(upd, i).av_princ.k_realm.utf8str_t_val); + if (ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val) { + for (j = 0; j < ULOG_ENTRY(upd, i).av_princ.k_components.k_components_len; j++) { + free(ULOG_ENTRY_PRINC(upd, i, j).k_data.utf8str_t_val); + } + free(ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val); + } + } + + /* + * Free av_mod_princ + */ + if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_PRINC) { + free(ULOG_ENTRY(upd, i).av_mod_princ.k_realm.utf8str_t_val); + if (ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val) { + for (j = 0; j < ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_len; j++) { + free(ULOG_ENTRY_MOD_PRINC(upd, i, j).k_data.utf8str_t_val); + } + free(ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val); + } + } + + /* + * Free av_mod_where + */ + if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_WHERE) && ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val) + free(ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val); + + /* + * Free av_pw_policy + */ + if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_POLICY) && ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val) + free(ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val); + + /* + * XXX: Free av_pw_hist + * + * For now, we just free the pointer + * to av_pw_hist_val, since we aren't + * populating this union member in + * the conv api function(s) anyways. + */ + if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_HIST) && ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val) + free(ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val); + + } + + /* + * Free up the pointer to kdbe_t_val + */ + free(upd->kdb_update.kdbe_t_val); + } + +/* END CSTYLED */ + + /* + * Bump up to next struct + */ + upd++; + } + + + /* + * Finally, free up the pointer to the bunched ulog entries + */ + free(updates); +} diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c new file mode 100644 index 0000000000..c4efc41e06 --- /dev/null +++ b/src/lib/kdb/kdb_log.c @@ -0,0 +1,928 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* #pragma ident "@(#)kdb_log.c 1.3 04/02/23 SMI" */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <k5-int.h> +#include <stdlib.h> +#include <limits.h> +#include <syslog.h> +#include "kdb5.h" +#include "kdb_log.h" + +/* + * This modules includes all the necessary functions that create and + * modify the Kerberos principal update and header logs. + */ + +#define getpagesize() sysconf(_SC_PAGESIZE) + +static int pagesize = 0; + +#define INIT_ULOG(ctx) \ + log_ctx = ctx->kdblog_context; \ + assert(log_ctx != NULL); \ + ulog = log_ctx->ulog; \ + assert(ulog != NULL) + +/* XXX */ +typedef unsigned long ulong_t; +typedef unsigned int uint_t; + +static int extend_file_to(int fd, uint_t new_size); + +krb5_error_code +ulog_lock(krb5_context ctx, int mode) +{ + kdb_log_context *log_ctx = NULL; + kdb_hlog_t *ulog = NULL; + + if (ctx == NULL) + return KRB5_LOG_ERROR; + if (ctx->kdblog_context == NULL || ctx->kdblog_context->iproprole == IPROP_NULL) + return 0; + INIT_ULOG(ctx); + return krb5_lock_file(ctx, log_ctx->ulogfd, mode); +} + +/* + * Sync update entry to disk. + */ +static krb5_error_code +ulog_sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd) +{ + ulong_t start, end, size; + krb5_error_code retval; + + if (ulog == NULL) + return (KRB5_LOG_ERROR); + + if (!pagesize) + pagesize = getpagesize(); + + start = ((ulong_t)upd) & (~(pagesize-1)); + + end = (((ulong_t)upd) + ulog->kdb_block + + (pagesize-1)) & (~(pagesize-1)); + + size = end - start; + if (retval = msync((caddr_t)start, size, MS_SYNC)) { + return (retval); + } + + return (0); +} + +/* + * Sync memory to disk for the update log header. + */ +static void +ulog_sync_header(kdb_hlog_t *ulog) +{ + + if (!pagesize) + pagesize = getpagesize(); + + if (msync((caddr_t)ulog, pagesize, MS_SYNC)) { + /* + * Couldn't sync to disk, let's panic + */ + syslog(LOG_ERR, "ulog_sync_header: could not sync to disk"); + abort(); + } +} + +/* + * Resizes the array elements. We reinitialize the update log rather than + * unrolling the the log and copying it over to a temporary log for obvious + * performance reasons. Slaves will subsequently do a full resync, but + * the need for resizing should be very small. + */ +static krb5_error_code +ulog_resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd, uint_t recsize) +{ + uint_t new_block, new_size; + + if (ulog == NULL) + return (KRB5_LOG_ERROR); + + new_size = sizeof (kdb_hlog_t); + + new_block = (recsize / ULOG_BLOCK) + 1; + new_block *= ULOG_BLOCK; + + new_size += ulogentries * new_block; + + if (new_size <= MAXLOGLEN) { + /* + * Reinit log with new block size + */ + (void) memset(ulog, 0, sizeof (kdb_hlog_t)); + + ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC; + ulog->db_version_num = KDB_VERSION; + ulog->kdb_state = KDB_STABLE; + ulog->kdb_block = new_block; + + ulog_sync_header(ulog); + + /* + * Time to expand log considering new block size + */ + if (extend_file_to(ulogfd, new_size) < 0) + return errno; + } else { + /* + * Can't map into file larger than MAXLOGLEN + */ + return (KRB5_LOG_ERROR); + } + + return (0); +} + +/* + * Adds an entry to the update log. + * The layout of the update log looks like: + * + * header log -> [ update header -> xdr(kdb_incr_update_t) ], ... + */ +krb5_error_code +ulog_add_update(krb5_context context, kdb_incr_update_t *upd) +{ + XDR xdrs; + kdbe_time_t ktime; + struct timeval timestamp; + kdb_ent_header_t *indx_log; + uint_t i, recsize; + ulong_t upd_size; + krb5_error_code retval; + kdb_sno_t cur_sno; + kdb_log_context *log_ctx; + kdb_hlog_t *ulog = NULL; + uint32_t ulogentries; + int ulogfd; + + INIT_ULOG(context); + ulogentries = log_ctx->ulogentries; + ulogfd = log_ctx->ulogfd; + + if (upd == NULL) + return (KRB5_LOG_ERROR); + + (void) gettimeofday(×tamp, NULL); + ktime.seconds = timestamp.tv_sec; + ktime.useconds = timestamp.tv_usec; + + upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd); + + recsize = sizeof (kdb_ent_header_t) + upd_size; + + if (recsize > ulog->kdb_block) { + if (retval = ulog_resize(ulog, ulogentries, ulogfd, recsize)) { + /* Resize element array failed */ + return (retval); + } + } + + cur_sno = ulog->kdb_last_sno; + + /* + * We need to overflow our sno, replicas will do full + * resyncs once they see their sno > than the masters. + */ + if (cur_sno == ULONG_MAX) + cur_sno = 1; + else + cur_sno++; + + /* + * We squirrel this away for finish_update() to index + */ + upd->kdb_entry_sno = cur_sno; + + i = (cur_sno - 1) % ulogentries; + + indx_log = (kdb_ent_header_t *)INDEX(ulog, i); + + (void) memset(indx_log, 0, ulog->kdb_block); + + indx_log->kdb_umagic = KDB_ULOG_MAGIC; + indx_log->kdb_entry_size = upd_size; + indx_log->kdb_entry_sno = cur_sno; + indx_log->kdb_time = upd->kdb_time = ktime; + indx_log->kdb_commit = upd->kdb_commit = FALSE; + + ulog->kdb_state = KDB_UNSTABLE; + + xdrmem_create(&xdrs, (char *)indx_log->entry_data, + indx_log->kdb_entry_size, XDR_ENCODE); + if (!xdr_kdb_incr_update_t(&xdrs, upd)) + return (KRB5_LOG_CONV); + + if (retval = ulog_sync_update(ulog, indx_log)) + return (retval); + + if (ulog->kdb_num < ulogentries) + ulog->kdb_num++; + + ulog->kdb_last_sno = cur_sno; + ulog->kdb_last_time = ktime; + + /* + * Since this is a circular array, once we circled, kdb_first_sno is + * always kdb_entry_sno + 1. + */ + if (cur_sno > ulogentries) { + i = upd->kdb_entry_sno % ulogentries; + indx_log = (kdb_ent_header_t *)INDEX(ulog, i); + ulog->kdb_first_sno = indx_log->kdb_entry_sno; + ulog->kdb_first_time = indx_log->kdb_time; + } else if (cur_sno == 1) { + ulog->kdb_first_sno = 1; + ulog->kdb_first_time = indx_log->kdb_time; + } + + ulog_sync_header(ulog); + + return (0); +} + +/* + * Mark the log entry as committed and sync the memory mapped log + * to file. + */ +krb5_error_code +ulog_finish_update(krb5_context context, kdb_incr_update_t *upd) +{ + krb5_error_code retval; + kdb_ent_header_t *indx_log; + uint_t i; + kdb_log_context *log_ctx; + kdb_hlog_t *ulog = NULL; + uint32_t ulogentries; + + INIT_ULOG(context); + ulogentries = log_ctx->ulogentries; + + i = (upd->kdb_entry_sno - 1) % ulogentries; + + indx_log = (kdb_ent_header_t *)INDEX(ulog, i); + + indx_log->kdb_commit = TRUE; + + ulog->kdb_state = KDB_STABLE; + + if (retval = ulog_sync_update(ulog, indx_log)) + return (retval); + + ulog_sync_header(ulog); + + return (0); +} + +/* + * Set the header log details on the slave and sync it to file. + */ +static void +ulog_finish_update_slave(kdb_hlog_t *ulog, kdb_last_t lastentry) +{ + + ulog->kdb_last_sno = lastentry.last_sno; + ulog->kdb_last_time = lastentry.last_time; + + ulog_sync_header(ulog); +} + +/* + * Delete an entry to the update log. + */ +krb5_error_code +ulog_delete_update(krb5_context context, kdb_incr_update_t *upd) +{ + + upd->kdb_deleted = TRUE; + + return (ulog_add_update(context, upd)); +} + +/* + * Used by the slave or master (during ulog_check) to update it's hash db from + * the incr update log. + * + * Must be called with lock held. + */ +krb5_error_code +ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args) +{ + krb5_db_entry *entry = NULL; + kdb_incr_update_t *upd = NULL, *fupd; + int i, no_of_updates; + krb5_error_code retval; + krb5_principal dbprinc = NULL; + kdb_last_t errlast; + char *dbprincstr = NULL; + kdb_log_context *log_ctx; + kdb_hlog_t *ulog = NULL; + + INIT_ULOG(context); + + no_of_updates = incr_ret->updates.kdb_ulog_t_len; + upd = incr_ret->updates.kdb_ulog_t_val; + fupd = upd; + + /* + * We reset last_sno and last_time to 0, if krb5_db2_db_put_principal + * or krb5_db2_db_delete_principal fail. + */ + errlast.last_sno = (unsigned int)0; + errlast.last_time.seconds = (unsigned int)0; + errlast.last_time.useconds = (unsigned int)0; + + if ((retval = krb5_db_open(context, db_args, + KRB5_KDB_OPEN_RW|KRB5_KDB_SRV_TYPE_ADMIN))) + goto cleanup; + + for (i = 0; i < no_of_updates; i++) { + int nentry = 1; + + if (!upd->kdb_commit) + continue; + + if (upd->kdb_deleted) { + dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len + + 1) * sizeof (char)); + + if (dbprincstr == NULL) { + retval = ENOMEM; + goto cleanup; + } + + (void) strncpy(dbprincstr, + (char *)upd->kdb_princ_name.utf8str_t_val, + (upd->kdb_princ_name.utf8str_t_len + 1)); + dbprincstr[upd->kdb_princ_name.utf8str_t_len] = 0; + + if (retval = krb5_parse_name(context, dbprincstr, + &dbprinc)) { + goto cleanup; + } + + free(dbprincstr); + + retval = krb5int_delete_principal_no_log(context, + dbprinc, + &nentry); + + if (dbprinc) + krb5_free_principal(context, dbprinc); + + if (retval) + goto cleanup; + } else { + entry = (krb5_db_entry *)malloc(sizeof (krb5_db_entry)); + + if (!entry) { + retval = errno; + goto cleanup; + } + + (void) memset(entry, 0, sizeof (krb5_db_entry)); + + if (retval = ulog_conv_2dbentry(context, entry, upd, 1)) + goto cleanup; + + retval = krb5int_put_principal_no_log(context, entry, + &nentry); + + if (entry) { + krb5_db_free_principal(context, entry, nentry); + free(entry); + entry = NULL; + } + if (retval) + goto cleanup; + } + + upd++; + } + +cleanup: + if (fupd) + ulog_free_entries(fupd, no_of_updates); + + if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { + if (retval) + ulog_finish_update_slave(ulog, errlast); + else + ulog_finish_update_slave(ulog, incr_ret->lastentry); + } + + return (retval); +} + +/* + * Validate the log file and resync any uncommitted update entries + * to the principal database. + * + * Must be called with lock held. + */ +static krb5_error_code +ulog_check(krb5_context context, kdb_hlog_t *ulog, char **db_args) +{ + XDR xdrs; + krb5_error_code retval = 0; + int i; + kdb_ent_header_t *indx_log; + kdb_incr_update_t *upd = NULL; + kdb_incr_result_t *incr_ret = NULL; + + ulog->kdb_state = KDB_STABLE; + + for (i = 0; i < ulog->kdb_num; i++) { + indx_log = (kdb_ent_header_t *)INDEX(ulog, i); + + if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) { + /* + * Update entry corrupted we should scream and die + */ + ulog->kdb_state = KDB_CORRUPT; + retval = KRB5_LOG_CORRUPT; + break; + } + + if (indx_log->kdb_commit == FALSE) { + ulog->kdb_state = KDB_UNSTABLE; + + incr_ret = (kdb_incr_result_t *) + malloc(sizeof (kdb_incr_result_t)); + if (incr_ret == NULL) { + retval = errno; + goto error; + } + + upd = (kdb_incr_update_t *) + malloc(sizeof (kdb_incr_update_t)); + if (upd == NULL) { + retval = errno; + goto error; + } + + (void) memset(upd, 0, sizeof (kdb_incr_update_t)); + xdrmem_create(&xdrs, (char *)indx_log->entry_data, + indx_log->kdb_entry_size, XDR_DECODE); + if (!xdr_kdb_incr_update_t(&xdrs, upd)) { + retval = KRB5_LOG_CONV; + goto error; + } + + incr_ret->updates.kdb_ulog_t_len = 1; + incr_ret->updates.kdb_ulog_t_val = upd; + + upd->kdb_commit = TRUE; + + /* + * We don't want to readd this update and just use the + * existing update to be propagated later on + */ + ulog_set_role(context, IPROP_NULL); + retval = ulog_replay(context, incr_ret, db_args); + + /* + * upd was freed by ulog_replay, we NULL + * the pointer in case we subsequently break from loop. + */ + upd = NULL; + if (incr_ret) { + free(incr_ret); + incr_ret = NULL; + } + ulog_set_role(context, IPROP_MASTER); + + if (retval) + goto error; + + /* + * We flag this as committed since this was + * the last entry before kadmind crashed, ergo + * the slaves have not seen this update before + */ + indx_log->kdb_commit = TRUE; + retval = ulog_sync_update(ulog, indx_log); + if (retval) + goto error; + + ulog->kdb_state = KDB_STABLE; + } + } + +error: + if (upd) + ulog_free_entries(upd, 1); + + free(incr_ret); + + ulog_sync_header(ulog); + + return (retval); +} + +/* + * Map the log file to memory for performance and simplicity. + * + * Called by: if iprop_enabled then ulog_map(); + * Assumes that the caller will terminate on ulog_map, hence munmap and + * closing of the fd are implicitly performed by the caller. + * Returns 0 on success else failure. + */ +krb5_error_code +ulog_map(krb5_context context, const char *logname, uint32_t ulogentries, + int caller, char **db_args) +{ + struct stat st; + krb5_error_code retval; + uint32_t ulog_filesize; + kdb_log_context *log_ctx; + kdb_hlog_t *ulog = NULL; + int ulogfd = -1; + + ulog_filesize = sizeof (kdb_hlog_t); + + if (stat(logname, &st) == -1) { + + if (caller == FKPROPLOG) { + /* + * File doesn't exist so we exit with kproplog + */ + return (errno); + } + + if ((ulogfd = open(logname, O_RDWR+O_CREAT, 0600)) == -1) { + return (errno); + } + + if (lseek(ulogfd, 0L, SEEK_CUR) == -1) { + return (errno); + } + + if ((caller == FKADMIND) || (caller == FKCOMMAND)) + ulog_filesize += ulogentries * ULOG_BLOCK; + + if (extend_file_to(ulogfd, ulog_filesize) < 0) + return errno; + } else { + + ulogfd = open(logname, O_RDWR, 0600); + if (ulogfd == -1) + /* + * Can't open existing log file + */ + return errno; + } + + if (caller == FKPROPLOG) { + fstat(ulogfd, &st); + ulog_filesize = st.st_size; + + ulog = (kdb_hlog_t *)mmap(0, ulog_filesize, + PROT_READ+PROT_WRITE, MAP_PRIVATE, ulogfd, 0); + } else { + /* + * else kadmind, kpropd, & kcommands should udpate stores + */ + ulog = (kdb_hlog_t *)mmap(0, MAXLOGLEN, + PROT_READ+PROT_WRITE, MAP_SHARED, ulogfd, 0); + } + + if ((int)(ulog) == -1) { + /* + * Can't map update log file to memory + */ + return (errno); + } + + if (!context->kdblog_context) { + if (!(log_ctx = malloc(sizeof (kdb_log_context)))) + return (errno); + memset(log_ctx, 0, sizeof(*log_ctx)); + context->kdblog_context = log_ctx; + } else + log_ctx = context->kdblog_context; + log_ctx->ulog = ulog; + log_ctx->ulogentries = ulogentries; + log_ctx->ulogfd = ulogfd; + + if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC) { + if (ulog->kdb_hmagic == 0) { + /* + * New update log + */ + (void) memset(ulog, 0, sizeof (kdb_hlog_t)); + + ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC; + ulog->db_version_num = KDB_VERSION; + ulog->kdb_state = KDB_STABLE; + ulog->kdb_block = ULOG_BLOCK; + if (!(caller == FKPROPLOG)) + ulog_sync_header(ulog); + } else { + return (KRB5_LOG_CORRUPT); + } + } + + if (caller == FKADMIND) { + retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE); + if (retval) + return retval; + switch (ulog->kdb_state) { + case KDB_STABLE: + case KDB_UNSTABLE: + /* + * Log is currently un/stable, check anyway + */ + retval = ulog_check(context, ulog, db_args); + ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + if (retval == KRB5_LOG_CORRUPT) { + return (retval); + } + break; + case KDB_CORRUPT: + ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return (KRB5_LOG_CORRUPT); + default: + /* + * Invalid db state + */ + ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return (KRB5_LOG_ERROR); + } + } else if ((caller == FKPROPLOG) || (caller == FKPROPD)) { + /* + * kproplog and kpropd don't need to do anything else + */ + return (0); + } + + /* + * Reinit ulog if the log is being truncated or expanded after + * we have circled. + */ + retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE); + if (retval) + return retval; + if (ulog->kdb_num != ulogentries) { + if ((ulog->kdb_num != 0) && + ((ulog->kdb_last_sno > ulog->kdb_num) || + (ulog->kdb_num > ulogentries))) { + + (void) memset(ulog, 0, sizeof (kdb_hlog_t)); + + ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC; + ulog->db_version_num = KDB_VERSION; + ulog->kdb_state = KDB_STABLE; + ulog->kdb_block = ULOG_BLOCK; + + ulog_sync_header(ulog); + } + + /* + * Expand ulog if we have specified a greater size + */ + if (ulog->kdb_num < ulogentries) { + ulog_filesize += ulogentries * ulog->kdb_block; + + if (extend_file_to(ulogfd, ulog_filesize) < 0) { + ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return errno; + } + } + } + ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + + return (0); +} + +/* + * Get the last set of updates seen, (last+1) to n is returned. + */ +krb5_error_code +ulog_get_entries(krb5_context context, /* input - krb5 lib config */ + kdb_last_t last, /* input - slave's last sno */ + kdb_incr_result_t *ulog_handle) /* output - incr result for slave */ +{ + XDR xdrs; + kdb_ent_header_t *indx_log; + kdb_incr_update_t *upd; + uint_t indx, count, tdiff; + uint32_t sno; + krb5_error_code retval; + struct timeval timestamp; + kdb_log_context *log_ctx; + kdb_hlog_t *ulog = NULL; + uint32_t ulogentries; + + INIT_ULOG(context); + ulogentries = log_ctx->ulogentries; + + retval = ulog_lock(context, KRB5_LOCKMODE_SHARED); + if (retval) + return retval; + + /* + * Check to make sure we don't have a corrupt ulog first. + */ + if (ulog->kdb_state == KDB_CORRUPT) { + ulog_handle->ret = UPDATE_ERROR; + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return (KRB5_LOG_CORRUPT); + } + + gettimeofday(×tamp, NULL); + + tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds; + if (tdiff <= ULOG_IDLE_TIME) { + ulog_handle->ret = UPDATE_BUSY; + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return (0); + } + + /* + * We need to lock out other processes here, such as kadmin.local, + * since we are looking at the last_sno and looking up updates. So + * we can share with other readers. + */ + retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED); + if (retval) { + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + return (retval); + } + + /* + * We may have overflowed the update log or we shrunk the log, or + * the client's ulog has just been created. + */ + if ((last.last_sno > ulog->kdb_last_sno) || + (last.last_sno < ulog->kdb_first_sno) || + (last.last_sno == 0)) { + ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; + return (0); + } else if (last.last_sno <= ulog->kdb_last_sno) { + sno = last.last_sno; + + indx = (sno - 1) % ulogentries; + + indx_log = (kdb_ent_header_t *)INDEX(ulog, indx); + + /* + * Validate the time stamp just to make sure it was the same sno + */ + if ((indx_log->kdb_time.seconds == last.last_time.seconds) && + (indx_log->kdb_time.useconds == last.last_time.useconds)) { + + /* + * If we have the same sno we return success + */ + if (last.last_sno == ulog->kdb_last_sno) { + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + ulog_handle->ret = UPDATE_NIL; + return (0); + } + + count = ulog->kdb_last_sno - sno; + + ulog_handle->updates.kdb_ulog_t_val = + (kdb_incr_update_t *)malloc( + sizeof (kdb_incr_update_t) * count); + + upd = ulog_handle->updates.kdb_ulog_t_val; + + if (upd == NULL) { + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + ulog_handle->ret = UPDATE_ERROR; + return (errno); + } + + while (sno < ulog->kdb_last_sno) { + indx = sno % ulogentries; + + indx_log = (kdb_ent_header_t *) + INDEX(ulog, indx); + + (void) memset(upd, 0, + sizeof (kdb_incr_update_t)); + xdrmem_create(&xdrs, + (char *)indx_log->entry_data, + indx_log->kdb_entry_size, XDR_DECODE); + if (!xdr_kdb_incr_update_t(&xdrs, upd)) { + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + ulog_handle->ret = UPDATE_ERROR; + return (KRB5_LOG_CONV); + } + /* + * Mark commitment since we didn't + * want to decode and encode the + * incr update record the first time. + */ + upd->kdb_commit = indx_log->kdb_commit; + + upd++; + sno++; + } /* while */ + + ulog_handle->updates.kdb_ulog_t_len = count; + + ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; + ulog_handle->lastentry.last_time.seconds = + ulog->kdb_last_time.seconds; + ulog_handle->lastentry.last_time.useconds = + ulog->kdb_last_time.useconds; + ulog_handle->ret = UPDATE_OK; + + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + + return (0); + } else { + /* + * We have time stamp mismatch or we no longer have + * the slave's last sno, so we brute force it + */ + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + (void) krb5_db_unlock(context); + ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; + + return (0); + } + } + + /* + * Should never get here, return error + */ + (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK); + ulog_handle->ret = UPDATE_ERROR; + return (KRB5_LOG_ERROR); +} + +krb5_error_code +ulog_set_role(krb5_context ctx, iprop_role role) +{ + kdb_log_context *log_ctx; + + if (!ctx->kdblog_context) { + if (!(log_ctx = malloc(sizeof (kdb_log_context)))) + return (errno); + memset(log_ctx, 0, sizeof(*log_ctx)); + ctx->kdblog_context = log_ctx; + } else + log_ctx = ctx->kdblog_context; + + log_ctx->iproprole = role; + + return (0); +} + +/* + * Extend update log file. + */ +static int extend_file_to(int fd, uint_t new_size) +{ + int current_offset; + static const char zero[512] = { 0, }; + + current_offset = lseek(fd, 0, SEEK_END); + if (current_offset < 0) + return -1; + if (new_size > INT_MAX) { + errno = EINVAL; + return -1; + } + while (current_offset < new_size) { + int write_size, wrote_size; + write_size = new_size - current_offset; + if (write_size > 512) + write_size = 512; + wrote_size = write(fd, zero, write_size); + if (wrote_size < 0) + return -1; + if (wrote_size == 0) { + errno = EINVAL; /* XXX ?? */ + return -1; + } + current_offset += wrote_size; + write_size = new_size - current_offset; + } + return 0; +} diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports index dd9f95288b..6157ec3571 100644 --- a/src/lib/kdb/libkdb5.exports +++ b/src/lib/kdb/libkdb5.exports @@ -49,3 +49,12 @@ krb5_db_delete_policy krb5_db_free_policy krb5_def_store_mkey krb5_db_promote +ulog_map +ulog_set_role +ulog_free_entries +xdr_kdb_last_t +xdr_kdb_incr_result_t +xdr_kdb_fullresync_result_t +ulog_get_entries +ulog_replay +xdr_kdb_incr_update_t |