summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/kadm5/Makefile.in4
-rw-r--r--src/lib/kadm5/admin.h61
-rw-r--r--src/lib/kadm5/alt_prof.c63
-rw-r--r--src/lib/kadm5/clnt/Makefile.in7
-rw-r--r--src/lib/kadm5/clnt/client_init.c52
-rw-r--r--src/lib/kadm5/clnt/libkadm5clnt.exports1
-rw-r--r--src/lib/kadm5/srv/Makefile.in8
-rw-r--r--src/lib/kadm5/srv/libkadm5srv.exports1
-rw-r--r--src/lib/kadm5/srv/server_acl.c3
-rw-r--r--src/lib/kadm5/srv/server_acl.h4
-rw-r--r--src/lib/kadm5/srv/server_init.c38
-rw-r--r--src/lib/kdb/Makefile.in66
-rw-r--r--src/lib/kdb/iprop.x223
-rw-r--r--src/lib/kdb/iprop_xdr.c351
-rw-r--r--src/lib/kdb/kdb5.c234
-rw-r--r--src/lib/kdb/kdb_convert.c1017
-rw-r--r--src/lib/kdb/kdb_log.c928
-rw-r--r--src/lib/kdb/libkdb5.exports9
-rw-r--r--src/lib/krb5/error_tables/kdb5_err.et7
19 files changed, 3004 insertions, 73 deletions
diff --git a/src/lib/kadm5/Makefile.in b/src/lib/kadm5/Makefile.in
index bcb46cede3..8cc931acac 100644
--- a/src/lib/kadm5/Makefile.in
+++ b/src/lib/kadm5/Makefile.in
@@ -171,10 +171,12 @@ alt_prof.so alt_prof.po $(OUTPRE)alt_prof.$(OBJEXT): \
$(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/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 alt_prof.c
str_conv.so str_conv.po $(OUTPRE)str_conv.$(OBJEXT): \
diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h
index 06a77dce64..9013305b69 100644
--- a/src/lib/kadm5/admin.h
+++ b/src/lib/kadm5/admin.h
@@ -48,6 +48,7 @@
#define KADM5_ADMIN_SERVICE "kadmin/admin"
#define KADM5_CHANGEPW_SERVICE "kadmin/changepw"
#define KADM5_HIST_PRINCIPAL "kadmin/history"
+#define KADM5_KIPROP_HOST_SERVICE "kiprop"
typedef krb5_principal kadm5_princ_t;
typedef char *kadm5_policy_t;
@@ -107,32 +108,37 @@ typedef long kadm5_ret_t;
#define KADM5_REF_COUNT 0x080000
/* kadm5_config_params */
-#define KADM5_CONFIG_REALM 0x000001
-#define KADM5_CONFIG_DBNAME 0x000002
-#define KADM5_CONFIG_MKEY_NAME 0x000004
-#define KADM5_CONFIG_MAX_LIFE 0x000008
-#define KADM5_CONFIG_MAX_RLIFE 0x000010
-#define KADM5_CONFIG_EXPIRATION 0x000020
-#define KADM5_CONFIG_FLAGS 0x000040
-#define KADM5_CONFIG_ADMIN_KEYTAB 0x000080
-#define KADM5_CONFIG_STASH_FILE 0x000100
-#define KADM5_CONFIG_ENCTYPE 0x000200
-#define KADM5_CONFIG_ADBNAME 0x000400
-#define KADM5_CONFIG_ADB_LOCKFILE 0x000800
-/*#define KADM5_CONFIG_PROFILE 0x001000*/
-#define KADM5_CONFIG_ACL_FILE 0x002000
-#define KADM5_CONFIG_KADMIND_PORT 0x004000
-#define KADM5_CONFIG_ENCTYPES 0x008000
-#define KADM5_CONFIG_ADMIN_SERVER 0x010000
-#define KADM5_CONFIG_DICT_FILE 0x020000
-#define KADM5_CONFIG_MKEY_FROM_KBD 0x040000
-#define KADM5_CONFIG_KPASSWD_PORT 0x080000
-#define KADM5_CONFIG_OLD_AUTH_GSSAPI 0x100000
-#define KADM5_CONFIG_NO_AUTH 0x200000
-#define KADM5_CONFIG_AUTH_NOFALLBACK 0x400000
+#define KADM5_CONFIG_REALM 0x00000001
+#define KADM5_CONFIG_DBNAME 0x00000002
+#define KADM5_CONFIG_MKEY_NAME 0x00000004
+#define KADM5_CONFIG_MAX_LIFE 0x00000008
+#define KADM5_CONFIG_MAX_RLIFE 0x00000010
+#define KADM5_CONFIG_EXPIRATION 0x00000020
+#define KADM5_CONFIG_FLAGS 0x00000040
+#define KADM5_CONFIG_ADMIN_KEYTAB 0x00000080
+#define KADM5_CONFIG_STASH_FILE 0x00000100
+#define KADM5_CONFIG_ENCTYPE 0x00000200
+#define KADM5_CONFIG_ADBNAME 0x00000400
+#define KADM5_CONFIG_ADB_LOCKFILE 0x00000800
+/*#define KADM5_CONFIG_PROFILE 0x00001000*/
+#define KADM5_CONFIG_ACL_FILE 0x00002000
+#define KADM5_CONFIG_KADMIND_PORT 0x00004000
+#define KADM5_CONFIG_ENCTYPES 0x00008000
+#define KADM5_CONFIG_ADMIN_SERVER 0x00010000
+#define KADM5_CONFIG_DICT_FILE 0x00020000
+#define KADM5_CONFIG_MKEY_FROM_KBD 0x00040000
+#define KADM5_CONFIG_KPASSWD_PORT 0x00080000
+#define KADM5_CONFIG_OLD_AUTH_GSSAPI 0x00100000
+#define KADM5_CONFIG_NO_AUTH 0x00200000
+#define KADM5_CONFIG_AUTH_NOFALLBACK 0x00400000
#ifdef notyet /* Novell */
-#define KADM5_CONFIG_KPASSWD_SERVER 0x800000
+#define KADM5_CONFIG_KPASSWD_SERVER 0x00800000
#endif
+#define KADM5_CONFIG_IPROP_ENABLED 0x01000000
+#define KADM5_CONFIG_ULOG_SIZE 0x02000000
+#define KADM5_CONFIG_POLL_TIME 0x04000000
+#define KADM5_CONFIG_IPROP_LOGFILE 0x08000000
+#define KADM5_CONFIG_IPROP_PORT 0x10000000
/*
* permission bits
*/
@@ -250,6 +256,13 @@ typedef struct _kadm5_config_params {
krb5_flags flags;
krb5_key_salt_tuple *keysalts;
krb5_int32 num_keysalts;
+
+ bool_t iprop_enabled;
+ uint32_t iprop_ulogsize;
+ krb5_deltat iprop_poll_time;
+ char * iprop_logfile;
+/* char * iprop_server;*/
+ int iprop_port;
} kadm5_config_params;
/***********************************************************************
diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c
index c56ceac2ff..c8bc6b052d 100644
--- a/src/lib/kadm5/alt_prof.c
+++ b/src/lib/kadm5/alt_prof.c
@@ -24,6 +24,10 @@
* or implied warranty.
*
*/
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
/*
* alt_prof.c - Implement alternate profile file handling.
@@ -33,6 +37,7 @@
#include "adm_proto.h"
#include <stdio.h>
#include <ctype.h>
+#include <kdb_log.h>
static krb5_key_salt_tuple *copy_key_salt_tuple(ksalt, len)
krb5_key_salt_tuple *ksalt;
@@ -381,7 +386,7 @@ get_string_param(char **param_out, char *param_in,
}
/*
* Similar, for (host-order) port number, if not already set in the
- * output field; default is required.
+ * output field; default_value==0 means no default.
*/
static void
get_port_param(int *param_out, int param_in,
@@ -402,7 +407,7 @@ get_port_param(int *param_out, int param_in,
!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) {
*param_out = ivalue;
*mask_out |= mask_bit;
- } else {
+ } else if (default_value) {
*param_out = default_value;
*mask_out |= mask_bit;
}
@@ -475,6 +480,7 @@ krb5_error_code kadm5_get_config_params(context, use_kdc_config,
krb5_pointer aprofile = 0;
const char *hierarchy[4];
char *svalue;
+ krb5_int32 ivalue;
kadm5_config_params params, empty_params;
krb5_error_code kret = 0;
@@ -714,6 +720,59 @@ krb5_error_code kadm5_get_config_params(context, use_kdc_config,
krb5_xfree(svalue);
}
+ hierarchy[2] = "iprop_enable";
+
+ params.iprop_enabled = FALSE;
+ params.mask |= KADM5_CONFIG_IPROP_ENABLED;
+
+ if (params_in->mask & KADM5_CONFIG_IPROP_ENABLED) {
+ params.mask |= KADM5_CONFIG_IPROP_ENABLED;
+ params.iprop_enabled = params_in->iprop_enabled;
+ } else {
+ krb5_boolean bvalue;
+ if (aprofile &&
+ !krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) {
+ params.iprop_enabled = bvalue;
+ params.mask |= KADM5_CONFIG_IPROP_ENABLED;
+ }
+ }
+
+ if (!GET_STRING_PARAM(iprop_logfile, KADM5_CONFIG_IPROP_LOGFILE,
+ "iprop_logfile", NULL)) {
+ if (params.mask & KADM5_CONFIG_DBNAME) {
+ if (asprintf(&params.iprop_logfile, "%s.ulog", params.dbname) >= 0) {
+ params.mask |= KADM5_CONFIG_IPROP_LOGFILE;
+ }
+ }
+ }
+
+ GET_PORT_PARAM(iprop_port, KADM5_CONFIG_IPROP_PORT,
+ "iprop_port", 0);
+
+ hierarchy[2] = "iprop_master_ulogsize";
+
+ params.iprop_ulogsize = DEF_ULOGENTRIES;
+ params.mask |= KADM5_CONFIG_ULOG_SIZE;
+
+ if (params_in->mask & KADM5_CONFIG_ULOG_SIZE) {
+ params.mask |= KADM5_CONFIG_ULOG_SIZE;
+ params.iprop_ulogsize = params_in->iprop_ulogsize;
+ } else {
+ if (aprofile && !krb5_aprof_get_int32(aprofile, hierarchy,
+ TRUE, &ivalue)) {
+ if (ivalue > MAX_ULOGENTRIES)
+ params.iprop_ulogsize = MAX_ULOGENTRIES;
+ else if (ivalue <= 0)
+ params.iprop_ulogsize = DEF_ULOGENTRIES;
+ else
+ params.iprop_ulogsize = ivalue;
+ params.mask |= KADM5_CONFIG_ULOG_SIZE;
+ }
+ }
+
+ GET_DELTAT_PARAM(iprop_poll_time, KADM5_CONFIG_POLL_TIME,
+ "iprop_slave_poll", 2 * 60); /* 2m */
+
*params_out = params;
cleanup:
diff --git a/src/lib/kadm5/clnt/Makefile.in b/src/lib/kadm5/clnt/Makefile.in
index 8c0bce1056..69679a9c89 100644
--- a/src/lib/kadm5/clnt/Makefile.in
+++ b/src/lib/kadm5/clnt/Makefile.in
@@ -6,8 +6,8 @@ LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5
DEFS=
LIBBASE=kadm5clnt
-LIBMAJOR=5
-LIBMINOR=1
+LIBMAJOR=6
+LIBMINOR=0
STOBJLISTS=../OBJS.ST OBJS.ST
SHLIB_EXPDEPS=\
$(TOPLIBD)/libgssrpc$(SHLIBEXT) \
@@ -130,7 +130,8 @@ client_init.so client_init.po $(OUTPRE)client_init.$(OBJEXT): \
$(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/k5-err.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 \
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index 8fc3dc1e28..d5131cfdad 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -48,6 +48,8 @@
#include <kadm5/admin.h>
#include <kadm5/kadm_rpc.h>
#include "client_internal.h"
+#include <iprop_hdr.h>
+#include "iprop.h"
#include <gssrpc/rpc.h>
#include <gssapi/gssapi.h>
@@ -165,6 +167,8 @@ static kadm5_ret_t _kadm5_init_any(char *client_name,
struct hostent *hp;
int fd;
+ char *iprop_svc;
+ int iprop_enable = 0;
char full_svcname[BUFSIZ];
char *realm;
@@ -296,15 +300,37 @@ static kadm5_ret_t _kadm5_init_any(char *client_name,
goto cleanup;
}
+ /*
+ * If the service_name and client_name are iprop-centric,
+ * we need to clnttcp_create to the appropriate RPC prog.
+ */
+ iprop_svc = strdup(KIPROP_SVC_NAME);
+ if (iprop_svc == NULL)
+ return ENOMEM;
+
+ if (service_name != NULL &&
+ (strstr(service_name, iprop_svc) != NULL) &&
+ (strstr(client_name, iprop_svc) != NULL))
+ iprop_enable = 1;
+ else
+ iprop_enable = 0;
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = hp->h_addrtype;
(void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr,
sizeof(addr.sin_addr));
- addr.sin_port = htons((u_short) handle->params.kadmind_port);
+ if (iprop_enable)
+ addr.sin_port = htons((u_short) handle->params.iprop_port);
+ else
+ addr.sin_port = htons((u_short) handle->params.kadmind_port);
fd = RPC_ANYSOCK;
-
- handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0);
+
+ if (iprop_enable) {
+ handle->clnt = clnttcp_create(&addr, KRB5_IPROP_PROG, KRB5_IPROP_VERS,
+ &fd, 0, 0);
+ } else
+ handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0);
if (handle->clnt == NULL) {
code = KADM5_RPC_ERROR;
#ifdef DEBUG
@@ -326,6 +352,16 @@ static kadm5_ret_t _kadm5_init_any(char *client_name,
if (code)
goto error;
+ /*
+ * Bypass the remainder of the code and return straightaway
+ * if the gss service requested is kiprop
+ */
+ if (iprop_enable == 1) {
+ code = 0;
+ *server_handle = (void *) handle;
+ goto cleanup;
+ }
+
r = init_2(&handle->api_version, handle->clnt);
if (r == NULL) {
code = KADM5_RPC_ERROR;
@@ -794,3 +830,13 @@ krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
{
return krb5_init_context(ctx);
}
+
+/*
+ * Stub function for kadmin. It was created to eliminate the dependency on
+ * libkdb's ulog functions. The srv equivalent makes the actual calls.
+ */
+krb5_error_code
+kadm5_init_iprop(void *handle)
+{
+ return (0);
+}
diff --git a/src/lib/kadm5/clnt/libkadm5clnt.exports b/src/lib/kadm5/clnt/libkadm5clnt.exports
index f7f873e292..7f11f320ac 100644
--- a/src/lib/kadm5/clnt/libkadm5clnt.exports
+++ b/src/lib/kadm5/clnt/libkadm5clnt.exports
@@ -129,3 +129,4 @@ xdr_setkey3_arg
xdr_setkey_arg
xdr_setv4key_arg
xdr_ui_4
+kadm5_init_iprop
diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in
index 21628bd7e5..9889c1e222 100644
--- a/src/lib/kadm5/srv/Makefile.in
+++ b/src/lib/kadm5/srv/Makefile.in
@@ -12,8 +12,8 @@ DEFS=
##DOSLIBNAME = libkadm5srv.lib
LIBBASE=kadm5srv
-LIBMAJOR=5
-LIBMINOR=1
+LIBMAJOR=6
+LIBMINOR=0
STOBJLISTS=../OBJS.ST OBJS.ST
SHLIB_EXPDEPS=\
@@ -191,10 +191,12 @@ server_init.so server_init.po $(OUTPRE)server_init.$(OBJEXT): \
$(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/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 $(srcdir)/../../gssapi/generic/gssapiP_generic.h \
$(srcdir)/../../gssapi/generic/gssapi_generic.h $(srcdir)/../../gssapi/krb5/gssapiP_krb5.h \
diff --git a/src/lib/kadm5/srv/libkadm5srv.exports b/src/lib/kadm5/srv/libkadm5srv.exports
index 23a4ee1e56..a4d2156f77 100644
--- a/src/lib/kadm5/srv/libkadm5srv.exports
+++ b/src/lib/kadm5/srv/libkadm5srv.exports
@@ -161,3 +161,4 @@ xdr_setkey3_arg
xdr_setkey_arg
xdr_setv4key_arg
xdr_ui_4
+kadm5_init_iprop
diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
index bcfe35f848..6cc9492c37 100644
--- a/src/lib/kadm5/srv/server_acl.c
+++ b/src/lib/kadm5/srv/server_acl.c
@@ -1,7 +1,7 @@
/*
* lib/kadm5/srv/server_acl.c
*
- * Copyright 1995-2004, 2007 by the Massachusetts Institute of Technology.
+ * Copyright 1995-2004, 2007, 2008 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -66,6 +66,7 @@ static const aop_t acl_op_table[] = {
{ 'c', ACL_CHANGEPW },
{ 'i', ACL_INQUIRE },
{ 'l', ACL_LIST },
+ { 'p', ACL_IPROP },
{ 's', ACL_SETKEY },
{ 'x', ACL_ALL_MASK },
{ '*', ACL_ALL_MASK },
diff --git a/src/lib/kadm5/srv/server_acl.h b/src/lib/kadm5/srv/server_acl.h
index 5024730cf6..b0ed0bf3dd 100644
--- a/src/lib/kadm5/srv/server_acl.h
+++ b/src/lib/kadm5/srv/server_acl.h
@@ -1,7 +1,7 @@
/*
* lib/kadm5/srv/server_acl.h
*
- * Copyright 1995-2004, 2007 by the Massachusetts Institute of Technology.
+ * Copyright 1995-2004, 2007, 2008 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -58,6 +58,7 @@
/* #define ACL_EXTRACT 64 */
#define ACL_LIST 128
#define ACL_SETKEY 256
+#define ACL_IPROP 512
#define ACL_RENAME (ACL_ADD+ACL_DELETE)
#define ACL_ALL_MASK (ACL_ADD | \
@@ -66,6 +67,7 @@
ACL_CHANGEPW | \
ACL_INQUIRE | \
ACL_LIST | \
+ ACL_IPROP | \
ACL_SETKEY)
typedef struct _restriction {
diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c
index dbb7ff78e6..febf79bdf8 100644
--- a/src/lib/kadm5/srv/server_init.c
+++ b/src/lib/kadm5/srv/server_init.c
@@ -4,6 +4,10 @@
* $Id$
* $Source$
*/
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
@@ -16,8 +20,10 @@ static char *rcsid = "$Header$";
#include "k5-int.h" /* needed for gssapiP_krb5.h */
#include <kadm5/admin.h>
#include <krb5.h>
+#include <kdb_log.h>
#include "server_internal.h"
#include "osconf.h"
+#include "iprop_hdr.h"
/*
* Function check_handle
@@ -238,12 +244,26 @@ kadm5_ret_t kadm5_init(char *client_name, char *pass,
KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES)
+#define IPROP_REQUIRED_PARAMS \
+ (KADM5_CONFIG_IPROP_ENABLED | \
+ KADM5_CONFIG_IPROP_LOGFILE | \
+ KADM5_CONFIG_IPROP_PORT)
+
if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
krb5_free_context(handle->context);
free_db_args(handle);
free(handle);
return KADM5_MISSING_CONF_PARAMS;
}
+ if ((handle->params.mask & KADM5_CONFIG_IPROP_ENABLED) == KADM5_CONFIG_IPROP_ENABLED
+ && handle->params.iprop_enabled) {
+ if ((handle->params.mask & IPROP_REQUIRED_PARAMS) != IPROP_REQUIRED_PARAMS) {
+ krb5_free_context(handle->context);
+ free_db_args(handle);
+ free(handle);
+ return KADM5_MISSING_CONF_PARAMS;
+ }
+ }
ret = krb5_set_default_realm(handle->context, handle->params.realm);
if (ret) {
@@ -430,3 +450,21 @@ krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
}
return krb5int_init_context_kdc(ctx);
}
+
+krb5_error_code
+kadm5_init_iprop(void *handle, char **db_args)
+{
+ kadm5_server_handle_t iprop_h;
+ krb5_error_code retval;
+
+ iprop_h = handle;
+ if (iprop_h->params.iprop_enabled) {
+ ulog_set_role(iprop_h->context, IPROP_MASTER);
+ if ((retval = ulog_map(iprop_h->context,
+ iprop_h->params.iprop_logfile,
+ iprop_h->params.iprop_ulogsize,
+ FKCOMMAND, db_args)) != 0)
+ return (retval);
+ }
+ return (0);
+}
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(&timestamp, 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(&timestamp, 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
diff --git a/src/lib/krb5/error_tables/kdb5_err.et b/src/lib/krb5/error_tables/kdb5_err.et
index d6014acec2..b15af8c873 100644
--- a/src/lib/krb5/error_tables/kdb5_err.et
+++ b/src/lib/krb5/error_tables/kdb5_err.et
@@ -1,7 +1,7 @@
#
# lib/krb5/error_tables/kdb5_err.et
#
-# Copyright 1990 by the Massachusetts Institute of Technology.
+# Copyright 1990, 2008 by the Massachusetts Institute of Technology.
# All Rights Reserved.
#
# Export of this software from the United States of America may
@@ -75,6 +75,9 @@ ec KRB5_KDB_SERVER_INTERNAL_ERR, "Server error"
ec KRB5_KDB_ACCESS_ERROR, "Unable to access Kerberos database"
ec KRB5_KDB_INTERNAL_ERROR, "Kerberos database internal error"
ec KRB5_KDB_CONSTRAINT_VIOLATION, "Kerberos database constraints violated"
-
+ec KRB5_LOG_CONV, "Update log conversion error"
+ec KRB5_LOG_UNSTABLE, "Update log is unstable"
+ec KRB5_LOG_CORRUPT, "Update log is corrupt"
+ec KRB5_LOG_ERROR, "Generic update log error"
end