diff options
Diffstat (limited to 'src/kadmin')
-rw-r--r-- | src/kadmin/cli/kadmin.c | 8 | ||||
-rw-r--r-- | src/kadmin/passwd/Makefile.in | 45 | ||||
-rw-r--r-- | src/kadmin/server/Makefile.in | 140 | ||||
-rw-r--r-- | src/kadmin/server/misc.c | 59 | ||||
-rw-r--r-- | src/kadmin/server/misc.h | 39 | ||||
-rw-r--r-- | src/kadmin/server/network.c | 2020 | ||||
-rw-r--r-- | src/kadmin/server/ovsec_kadmd.c | 407 | ||||
-rw-r--r-- | src/kadmin/server/schpw.c | 241 | ||||
-rw-r--r-- | src/kadmin/testing/util/Makefile.in | 6 |
9 files changed, 2369 insertions, 596 deletions
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c index efc645b..b2bda15 100644 --- a/src/kadmin/cli/kadmin.c +++ b/src/kadmin/cli/kadmin.c @@ -1481,6 +1481,14 @@ void kadmin_getprinc(argc, argv) free(canon); return; } + free(canon); + canon = NULL; + retval = krb5_unparse_name(context, dprinc.principal, &canon); + if (retval) { + com_err("get_principal", retval, "while canonicalizing principal"); + krb5_free_principal(context, princ); + return; + } retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon); if (retval) { com_err("get_principal", retval, "while unparsing modname"); diff --git a/src/kadmin/passwd/Makefile.in b/src/kadmin/passwd/Makefile.in index 6a7aa19..83781fa 100644 --- a/src/kadmin/passwd/Makefile.in +++ b/src/kadmin/passwd/Makefile.in @@ -29,29 +29,26 @@ clean:: # Makefile dependencies follow. This must be the last section in # the Makefile.in file # -$(OUTPRE)tty_kpasswd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ - $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.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/k5-platform.h $(SRCTOP)/include/k5-thread.h \ - $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h kpasswd.h \ - kpasswd_strings.h tty_kpasswd.c -$(OUTPRE)kpasswd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ - $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.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/k5-platform.h $(SRCTOP)/include/k5-thread.h \ - $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h kpasswd.c \ - kpasswd.h kpasswd_strings.h +$(OUTPRE)tty_kpasswd.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ + $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ + $(BUILDTOP)/include/krb5/krb5.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/kdb.h \ + $(SRCTOP)/include/krb5.h kpasswd.h kpasswd_strings.h \ + tty_kpasswd.c +$(OUTPRE)kpasswd.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ + $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ + $(BUILDTOP)/include/krb5/krb5.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/kdb.h \ + $(SRCTOP)/include/krb5.h kpasswd.c kpasswd.h kpasswd_strings.h $(OUTPRE)kpasswd_strings.$(OBJEXT): $(COM_ERR_DEPS) \ kpasswd_strings.c diff --git a/src/kadmin/server/Makefile.in b/src/kadmin/server/Makefile.in index 6b8307e..be2d2e3 100644 --- a/src/kadmin/server/Makefile.in +++ b/src/kadmin/server/Makefile.in @@ -13,8 +13,8 @@ PROG_LIBPATH=-L$(TOPLIBD) PROG_RPATH=$(KRB5_LIBDIR) PROG = kadmind -OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o server_glue_v1.o ipropd_svc.o -SRCS = kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c schpw.c misc.c server_glue_v1.c ipropd_svc.c +OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o server_glue_v1.o ipropd_svc.o network.o +SRCS = kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c schpw.c misc.c server_glue_v1.c ipropd_svc.c network.c all:: $(PROG) @@ -33,42 +33,41 @@ clean:: # the Makefile.in file # $(OUTPRE)kadm_rpc_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \ - $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ - $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \ - $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \ - $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.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/k5-platform.h \ - $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ - $(SRCTOP)/include/krb5.h kadm_rpc_svc.c misc.h -$(OUTPRE)server_stubs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \ - $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ - $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \ - $(BUILDTOP)/include/kadm5/server_acl.h $(BUILDTOP)/include/kadm5/server_internal.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \ + $(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/gssrpc/types.h \ + $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \ + $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ + $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_internal.h \ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.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/k5-platform.h $(SRCTOP)/include/k5-thread.h \ - $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h misc.h \ - server_stubs.c -$(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ + $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h kadm_rpc_svc.c \ + misc.h +$(OUTPRE)server_stubs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \ + $(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/gssrpc/types.h \ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \ $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_acl.h \ $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \ - $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(BUILDTOP)/lib/gssapi/generic/gssapi_err_generic.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.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/kdb.h \ + $(SRCTOP)/include/krb5.h misc.h server_stubs.c +$(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ + $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ + $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \ + $(BUILDTOP)/include/kadm5/server_acl.h $(BUILDTOP)/include/kadm5/server_internal.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(BUILDTOP)/lib/gssapi/generic/gssapi_err_generic.h \ $(BUILDTOP)/lib/gssapi/krb5/gssapi_err_krb5.h $(BUILDTOP)/lib/gssapi/krb5/gssapi_krb5.h \ $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.h $(SRCTOP)/include/gssrpc/auth.h \ $(SRCTOP)/include/gssrpc/auth_gss.h $(SRCTOP)/include/gssrpc/auth_gssapi.h \ @@ -85,8 +84,9 @@ $(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.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 \ - $(SRCTOP)/lib/gssapi/generic/gssapiP_generic.h $(SRCTOP)/lib/gssapi/generic/gssapi_generic.h \ - $(SRCTOP)/lib/gssapi/krb5/gssapiP_krb5.h misc.h ovsec_kadmd.c + $(SRCTOP)/lib/gssapi/generic/gssapiP_generic.h $(SRCTOP)/lib/gssapi/generic/gssapi_ext.h \ + $(SRCTOP)/lib/gssapi/generic/gssapi_generic.h $(SRCTOP)/lib/gssapi/krb5/gssapiP_krb5.h \ + misc.h ovsec_kadmd.c $(OUTPRE)schpw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ @@ -109,46 +109,66 @@ $(OUTPRE)misc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \ $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ - $(BUILDTOP)/include/kadm5/server_internal.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/k5-buf.h $(SRCTOP)/include/k5-err.h \ - $(SRCTOP)/include/k5-gmt_mktime.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 \ + $(BUILDTOP)/include/kadm5/server_acl.h $(BUILDTOP)/include/kadm5/server_internal.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/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.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 misc.c misc.h -$(OUTPRE)server_glue_v1.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ - $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.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/k5-platform.h $(SRCTOP)/include/k5-thread.h \ - $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h misc.h \ - server_glue_v1.c +$(OUTPRE)server_glue_v1.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ + $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ + $(BUILDTOP)/include/krb5/krb5.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/kdb.h \ + $(SRCTOP)/include/krb5.h misc.h server_glue_v1.c $(OUTPRE)ipropd_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ + $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \ + $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \ + $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/lib/gssapi/krb5/gssapi_krb5.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.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 \ + $(SRCTOP)/include/iprop_hdr.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/kdb_log.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/lib/kadm5/srv/server_acl.h ipropd_svc.c misc.h +$(OUTPRE)network.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \ $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_internal.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ - $(BUILDTOP)/lib/gssapi/krb5/gssapi_krb5.h $(COM_ERR_DEPS) \ - $(SRCTOP)/include/adm_proto.h $(SRCTOP)/include/gssrpc/auth.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/adm_proto.h \ + $(SRCTOP)/include/cm.h $(SRCTOP)/include/fake-addrinfo.h \ + $(SRCTOP)/include/foreachaddr.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 \ - $(SRCTOP)/include/iprop_hdr.h $(SRCTOP)/include/k5-platform.h \ - $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ - $(SRCTOP)/include/kdb_log.h $(SRCTOP)/include/krb5.h \ - $(SRCTOP)/lib/kadm5/srv/server_acl.h ipropd_svc.c misc.h + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-gmt_mktime.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 misc.h network.c diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c index 06e3cdb..1725fbf 100644 --- a/src/kadmin/server/misc.c +++ b/src/kadmin/server/misc.c @@ -6,6 +6,7 @@ #include <k5-int.h> #include <kdb.h> #include <kadm5/server_internal.h> +#include <kadm5/server_acl.h> #include "misc.h" /* @@ -95,19 +96,61 @@ randkey_principal_wrapper_3(void *server_handle, } kadm5_ret_t -schpw_util_wrapper(void *server_handle, krb5_principal princ, +schpw_util_wrapper(void *server_handle, + krb5_principal client, + krb5_principal target, + krb5_boolean initial_flag, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { - kadm5_ret_t ret; + kadm5_ret_t ret; + kadm5_server_handle_t handle = server_handle; + krb5_boolean access_granted; + krb5_boolean self; + + /* + * If no target is explicitly provided, then the target principal + * is the client principal. + */ + if (target == NULL) + target = client; + + /* + * A principal can always change its own password, as long as it + * has an initial ticket and meets the minimum password lifetime + * requirement. + */ + self = krb5_principal_compare(handle->context, client, target); + if (self) { + ret = check_min_life(server_handle, target, msg_ret, msg_len); + if (ret != 0) + return ret; - ret = check_min_life(server_handle, princ, msg_ret, msg_len); - if (ret) - return ret; + access_granted = initial_flag; + } else + access_granted = FALSE; + + if (!access_granted && + kadm5int_acl_check_krb(handle->context, client, + ACL_CHANGEPW, target, NULL)) { + /* + * Otherwise, principals with appropriate privileges can change + * any password + */ + access_granted = TRUE; + } + + if (access_granted) { + ret = kadm5_chpass_principal_util(server_handle, + target, + new_pw, ret_pw, + msg_ret, msg_len); + } else { + ret = KADM5_AUTH_CHANGEPW; + strlcpy(msg_ret, "Unauthorized request", msg_len); + } - return kadm5_chpass_principal_util(server_handle, princ, - new_pw, ret_pw, - msg_ret, msg_len); + return ret; } kadm5_ret_t diff --git a/src/kadmin/server/misc.h b/src/kadmin/server/misc.h index f93cdaa..b8aef57 100644 --- a/src/kadmin/server/misc.h +++ b/src/kadmin/server/misc.h @@ -3,6 +3,14 @@ * */ +#ifndef _MISC_H +#define _MISC_H 1 + +typedef struct _krb5_fulladdr { + krb5_address * address; + krb5_ui_4 port; +} krb5_fulladdr; + void log_badauth(OM_uint32 major, OM_uint32 minor, struct sockaddr_in *addr, char *data); @@ -11,6 +19,7 @@ int setup_gss_names(struct svc_req *, gss_buffer_desc *, gss_buffer_desc *); + kadm5_ret_t chpass_principal_wrapper_3(void *server_handle, krb5_principal principal, @@ -28,7 +37,8 @@ randkey_principal_wrapper_3(void *server_handle, krb5_keyblock **keys, int *n_keys); kadm5_ret_t -schpw_util_wrapper(void *server_handle, krb5_principal princ, +schpw_util_wrapper(void *server_handle, krb5_principal client, + krb5_principal target, krb5_boolean initial_flag, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len); @@ -45,14 +55,14 @@ kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name, krb5_error_code process_chpw_request(krb5_context context, void *server_handle, - char *realm, int s, + char *realm, krb5_keytab keytab, - struct sockaddr_in *sockin, + krb5_fulladdr *local_faddr, + krb5_fulladdr *remote_faddr, krb5_data *req, krb5_data *rep); -#ifdef SVC_GETARGS -void kadm_1(struct svc_req *, SVCXPRT *); -#endif +void kadm_1(struct svc_req *, SVCXPRT *); +void krb5_iprop_prog_1(struct svc_req *, SVCXPRT *); void trunc_name(size_t *len, char **dots); @@ -60,6 +70,21 @@ int gss_to_krb5_name_1(struct svc_req *rqstp, krb5_context ctx, gss_name_t gss_name, krb5_principal *princ, gss_buffer_t gss_str); + +extern volatile int signal_request_exit; +extern volatile int signal_request_hup; + +void reset_db(void); + +void log_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, char *data); + +/* network.c */ +krb5_error_code setup_network(void *handle, const char *prog); +krb5_error_code listen_and_process(void *handle, const char *prog); +krb5_error_code closedown_network(void *handle, const char *prog); + + void krb5_iprop_prog_1(struct svc_req *rqstp, SVCXPRT *transp); @@ -68,3 +93,5 @@ kiprop_get_adm_host_srv_name(krb5_context, const char *, char **); + +#endif /* _MISC_H */ diff --git a/src/kadmin/server/network.c b/src/kadmin/server/network.c new file mode 100644 index 0000000..d0f8afa --- /dev/null +++ b/src/kadmin/server/network.c @@ -0,0 +1,2020 @@ +/* + * kadmin/server/network.c + * + * Copyright 1990,2000,2007,2008 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Network code for Kerberos v5 kadmin server (based on KDC code). + */ + +#include "k5-int.h" +#include "com_err.h" +#include "kadm5/admin.h" +#include "kadm5/server_internal.h" +#include "kadm5/kadm_rpc.h" +#include "iprop.h" +#include "adm_proto.h" +#include "misc.h" +#include <sys/ioctl.h> +#include <syslog.h> + +#include <stddef.h> +#include <ctype.h> +#include "port-sockets.h" +#include "socket-utils.h" + +#ifdef HAVE_NETINET_IN_H +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SOCKIO_H +/* for SIOCGIFCONF, etc. */ +#include <sys/sockio.h> +#endif +#include <sys/time.h> +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include <arpa/inet.h> + +#ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */ +#include <net/if.h> +#endif + +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> /* FIONBIO */ +#endif + +#include "fake-addrinfo.h" + +/* XXX */ +#define KDC5_NONET (-1779992062L) + +/* Misc utility routines. */ +static void +set_sa_port(struct sockaddr *addr, int port) +{ + switch (addr->sa_family) { + case AF_INET: + sa2sin(addr)->sin_port = port; + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + sa2sin6(addr)->sin6_port = port; + break; +#endif + default: + break; + } +} + +static int ipv6_enabled() +{ +#ifdef KRB5_USE_INET6 + static int result = -1; + if (result == -1) { + int s; + s = socket(AF_INET6, SOCK_STREAM, 0); + if (s >= 0) { + result = 1; + close(s); + } else + result = 0; + } + return result; +#else + return 0; +#endif +} + +static int +setreuseaddr(int sock, int value) +{ + return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); +} + +#if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY) +static int +setv6only(int sock, int value) +{ + return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value)); +} +#endif + +/* Use RFC 3542 API below, but fall back from IPV6_RECVPKTINFO to + IPV6_PKTINFO for RFC 2292 implementations. */ +#ifndef IPV6_RECVPKTINFO +#define IPV6_RECVPKTINFO IPV6_PKTINFO +#endif +/* Parallel, though not standardized. */ +#ifndef IP_RECVPKTINFO +#define IP_RECVPKTINFO IP_PKTINFO +#endif + +static int +set_pktinfo(int sock, int family) +{ + int sockopt = 1; + int option = 0, proto = 0; + + switch (family) { +#if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO) + case AF_INET: + proto = IPPROTO_IP; + option = IP_RECVPKTINFO; + break; +#endif +#if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) + case AF_INET6: + proto = IPPROTO_IPV6; + option = IPV6_RECVPKTINFO; + break; +#endif + default: + return EINVAL; + } + if (setsockopt(sock, proto, option, &sockopt, sizeof(sockopt))) + return errno; + return 0; +} + + +static const char *paddr (struct sockaddr *sa) +{ + static char buf[100]; + char portbuf[10]; + if (getnameinfo(sa, socklen(sa), + buf, sizeof(buf), portbuf, sizeof(portbuf), + NI_NUMERICHOST|NI_NUMERICSERV)) + strlcpy(buf, "<unprintable>", sizeof(buf)); + else { + unsigned int len = sizeof(buf) - strlen(buf); + char *p = buf + strlen(buf); + if (len > 2+strlen(portbuf)) { + *p++ = '.'; + len--; + strncpy(p, portbuf, len); + } + } + return buf; +} + +/* kadmin data. */ + +enum kadm_conn_type { CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, + CONN_TCP, CONN_ROUTING, CONN_RPC_LISTENER, CONN_RPC }; + +/* Per-connection info. */ +struct connection { + int fd; + enum kadm_conn_type type; + void (*service)(void *handle, struct connection *, const char *, int); + union { + /* Type-specific information. */ + struct { + /* connection */ + struct sockaddr_storage addr_s; + socklen_t addrlen; + char addrbuf[56]; + krb5_fulladdr faddr; + krb5_address kaddr; + /* incoming */ + size_t bufsiz; + size_t offset; + char *buffer; + size_t msglen; + /* outgoing */ + krb5_data *response; + unsigned char lenbuf[4]; + sg_buf sgbuf[2]; + sg_buf *sgp; + int sgnum; + /* crude denial-of-service avoidance support */ + time_t start_time; + } tcp; + struct { + SVCXPRT *transp; + } rpc; + } u; +}; + + +#define SET(TYPE) struct { TYPE *data; int n, max; } + +/* Start at the top and work down -- this should allow for deletions + without disrupting the iteration, since we delete by overwriting + the element to be removed with the last element. */ +#define FOREACH_ELT(set,idx,vvar) \ + for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--) + +#define GROW_SET(set, incr, tmpptr) \ + (((int)(set.max + incr) < set.max \ + || (((size_t)((int)(set.max + incr) * sizeof(set.data[0])) \ + / sizeof(set.data[0])) \ + != (set.max + incr))) \ + ? 0 /* overflow */ \ + : ((tmpptr = realloc(set.data, \ + (int)(set.max + incr) * sizeof(set.data[0]))) \ + ? (set.data = tmpptr, set.max += incr, 1) \ + : 0)) + +/* 1 = success, 0 = failure */ +#define ADD(set, val, tmpptr) \ + ((set.n < set.max || GROW_SET(set, 10, tmpptr)) \ + ? (set.data[set.n++] = val, 1) \ + : 0) + +#define DEL(set, idx) \ + (set.data[idx] = set.data[--set.n], 0) + +#define FREE_SET_DATA(set) \ + (free(set.data), set.data = 0, set.max = 0, set.n = 0) + + +/* Set<struct connection *> connections; */ +static SET(struct connection *) connections; +#define n_sockets connections.n +#define conns connections.data + +/* Set<u_short> udp_port_data, tcp_port_data; */ +static SET(u_short) udp_port_data, tcp_port_data; + +struct rpc_svc_data { + u_short port; + u_long prognum; + u_long versnum; + void (*dispatch)(); +}; + +static SET(struct rpc_svc_data) rpc_svc_data; + +#include "cm.h" + +static struct select_state sstate; +static fd_set rpc_listenfds; + +static krb5_error_code add_udp_port(int port) +{ + int i; + void *tmp; + u_short val; + u_short s_port = port; + + if (s_port != port) + return EINVAL; + + FOREACH_ELT (udp_port_data, i, val) + if (s_port == val) + return 0; + if (!ADD(udp_port_data, s_port, tmp)) + return ENOMEM; + return 0; +} + +static krb5_error_code add_tcp_port(int port) +{ + int i; + void *tmp; + u_short val; + u_short s_port = port; + + if (s_port != port) + return EINVAL; + + FOREACH_ELT (tcp_port_data, i, val) + if (s_port == val) + return 0; + if (!ADD(tcp_port_data, s_port, tmp)) + return ENOMEM; + return 0; +} + +static krb5_error_code add_rpc_service(int port, u_long prognum, u_long versnum, + void (*dispatch)()) +{ + int i; + void *tmp; + struct rpc_svc_data svc, val; + + svc.port = port; + if (svc.port != port) + return EINVAL; + svc.prognum = prognum; + svc.versnum = versnum; + svc.dispatch = dispatch; + + FOREACH_ELT (rpc_svc_data, i, val) { + if (val.port == port) + return 0; + } + if (!ADD(rpc_svc_data, svc, tmp)) + return ENOMEM; + return 0; +} + + +#define USE_AF AF_INET +#define USE_TYPE SOCK_DGRAM + + +#define USE_AF AF_INET +#define USE_TYPE SOCK_DGRAM +#define USE_PROTO 0 +#define SOCKET_ERRNO errno +#include "foreachaddr.h" + +struct socksetup { + const char *prog; + krb5_error_code retval; + int udp_flags; +#define UDP_DO_IPV4 1 +#define UDP_DO_IPV6 2 +}; + +static struct connection * +add_fd (struct socksetup *data, int sock, enum kadm_conn_type conntype, + void (*service)(void *handle, struct connection *, const char *, int)) +{ + struct connection *newconn; + void *tmp; + +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { + data->retval = EMFILE; /* XXX */ + com_err(data->prog, 0, + "file descriptor number %d too high", sock); + return 0; + } +#endif + newconn = (struct connection *)malloc(sizeof(*newconn)); + if (newconn == NULL) { + data->retval = ENOMEM; + com_err(data->prog, ENOMEM, + "cannot allocate storage for connection info"); + return 0; + } + if (!ADD(connections, newconn, tmp)) { + data->retval = ENOMEM; + com_err(data->prog, ENOMEM, "cannot save socket info"); + free(newconn); + return 0; + } + + memset(newconn, 0, sizeof(*newconn)); + newconn->type = conntype; + newconn->fd = sock; + newconn->service = service; + return newconn; +} + +static void process_packet(void *handle, struct connection *, const char *, int); +static void accept_tcp_connection(void *handle, struct connection *, const char *, int); +static void process_tcp_connection(void *handle, struct connection *, const char *, int); +static void accept_rpc_connection(void *handle, struct connection *, const char *, int); +static void process_rpc_connection(void *handle, struct connection *, const char *, int); + +static struct connection * +add_udp_fd (struct socksetup *data, int sock, int pktinfo) +{ + return add_fd(data, sock, pktinfo ? CONN_UDP_PKTINFO : CONN_UDP, + process_packet); +} + +static struct connection * +add_tcp_listener_fd (struct socksetup *data, int sock) +{ + return add_fd(data, sock, CONN_TCP_LISTENER, accept_tcp_connection); +} + +static struct connection * +add_tcp_data_fd (struct socksetup *data, int sock) +{ + return add_fd(data, sock, CONN_TCP, process_tcp_connection); +} + +static void +delete_fd (struct connection *xconn) +{ + struct connection *conn; + int i; + + FOREACH_ELT(connections, i, conn) + if (conn == xconn) { + DEL(connections, i); + break; + } + free(xconn); +} + +static struct connection * +add_rpc_listener_fd (struct socksetup *data, struct rpc_svc_data *svc, int sock) +{ + struct connection *conn; + + conn = add_fd(data, sock, CONN_RPC_LISTENER, accept_rpc_connection); + if (conn == NULL) + return NULL; + + conn->u.rpc.transp = svctcp_create(sock, 0, 0); + if (conn->u.rpc.transp == NULL) { + krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %s; continuing", + strerror(errno)); + delete_fd(conn); + return NULL; + } + + if (!svc_register(conn->u.rpc.transp, svc->prognum, svc->versnum, + svc->dispatch, 0)) { + krb5_klog_syslog(LOG_ERR, "Cannot register RPC service: %s; continuing", + strerror(errno)); + delete_fd(conn); + return NULL; + } + + return conn; +} + +static struct connection * +add_rpc_data_fd (struct socksetup *data, int sock) +{ + return add_fd(data, sock, CONN_RPC, process_rpc_connection); +} + +static const int one = 1; + +static int +setnbio(int sock) +{ + return ioctlsocket(sock, FIONBIO, (const void *)&one); +} + +static int +setkeepalive(int sock) +{ + return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)); +} + +static int +setnolinger(int s) +{ + static const struct linger ling = { 0, 0 }; + return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); +} + +/* Returns -1 or socket fd. */ +static int +setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr) +{ + int sock; + + sock = socket(addr->sa_family, SOCK_STREAM, 0); + if (sock == -1) { + com_err(data->prog, errno, "Cannot create TCP server socket on %s", + paddr(addr)); + return -1; + } + set_cloexec_fd(sock); +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { + close(sock); + com_err(data->prog, 0, "TCP socket fd number %d (for %s) too high", + sock, paddr(addr)); + return -1; + } +#endif + if (setreuseaddr(sock, 1) < 0) + com_err(data->prog, errno, + "Cannot enable SO_REUSEADDR on fd %d", sock); +#ifdef KRB5_USE_INET6 + if (addr->sa_family == AF_INET6) { +#ifdef IPV6_V6ONLY + if (setv6only(sock, 1)) + com_err(data->prog, errno, "setsockopt(%d,IPV6_V6ONLY,1) failed", + sock); + else + com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked", + sock); +#else + krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support"); +#endif /* IPV6_V6ONLY */ + } +#endif /* KRB5_USE_INET6 */ + if (bind(sock, addr, socklen(addr)) == -1) { + com_err(data->prog, errno, + "Cannot bind TCP server socket on %s", paddr(addr)); + close(sock); + return -1; + } + if (listen(sock, 5) < 0) { + com_err(data->prog, errno, "Cannot listen on TCP server socket on %s", + paddr(addr)); + close(sock); + return -1; + } + if (setnbio(sock)) { + com_err(data->prog, errno, + "cannot set listening tcp socket on %s non-blocking", + paddr(addr)); + close(sock); + return -1; + } + if (setnolinger(sock)) { + com_err(data->prog, errno, "disabling SO_LINGER on TCP socket on %s", + paddr(addr)); + close(sock); + return -1; + } + return sock; +} + +/* Returns -1 or socket fd. */ +static int +setup_a_rpc_listener(struct socksetup *data, struct sockaddr *addr) +{ + int sock; + + sock = socket(addr->sa_family, SOCK_STREAM, 0); + if (sock == -1) { + com_err(data->prog, errno, "Cannot create RPC server socket on %s", + paddr(addr)); + return -1; + } + set_cloexec_fd(sock); +#ifndef _WIN32 + if (sock >= FD_SETSIZE) { + close(sock); + com_err(data->prog, 0, "RPC socket fd number %d (for %s) too high", + sock, paddr(addr)); + return -1; + } +#endif + if (setreuseaddr(sock, 1) < 0) + com_err(data->prog, errno, + "Cannot enable SO_REUSEADDR on fd %d", sock); + if (bind(sock, addr, socklen(addr)) == -1) { + com_err(data->prog, errno, + "Cannot bind RPC server socket on %s", paddr(addr)); + close(sock); + return -1; + } + return sock; +} + +static int +setup_tcp_listener_ports(struct socksetup *data) +{ + struct sockaddr_in sin4; +#ifdef KRB5_USE_INET6 + struct sockaddr_in6 sin6; +#endif + int i, port; + + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sin4.sin_len = sizeof(sin4); +#endif + sin4.sin_addr.s_addr = INADDR_ANY; + +#ifdef KRB5_USE_INET6 + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + sin6.sin6_len = sizeof(sin6); +#endif + sin6.sin6_addr = in6addr_any; +#endif + + FOREACH_ELT (tcp_port_data, i, port) { + int s4, s6; + + set_sa_port((struct sockaddr *)&sin4, htons(port)); + if (!ipv6_enabled()) { + s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4); + if (s4 < 0) + return -1; + s6 = -1; + } else { +#ifndef KRB5_USE_INET6 + abort(); +#else + s4 = s6 = -1; + + set_sa_port((struct sockaddr *)&sin6, htons(port)); + + s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6); + if (s6 < 0) + return -1; + + s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4); +#endif /* KRB5_USE_INET6 */ + } + + /* Sockets are created, prepare to listen on them. */ + if (s4 >= 0) { + if (add_tcp_listener_fd(data, s4) == NULL) + close(s4); + else { + FD_SET(s4, &sstate.rfds); + if (s4 >= sstate.max) + sstate.max = s4 + 1; + krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s", + s4, paddr((struct sockaddr *)&sin4)); + } + } +#ifdef KRB5_USE_INET6 + if (s6 >= 0) { + if (add_tcp_listener_fd(data, s6) == NULL) { + close(s6); + s6 = -1; + } else { + FD_SET(s6, &sstate.rfds); + if (s6 >= sstate.max) + sstate.max = s6 + 1; + krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s", + s6, paddr((struct sockaddr *)&sin6)); + } + if (s4 < 0) + krb5_klog_syslog(LOG_INFO, + "assuming IPv6 socket accepts IPv4"); + } +#endif + } + return 0; +} + +static int +setup_rpc_listener_ports(struct socksetup *data) +{ + struct sockaddr_in sin4; + int i; + struct rpc_svc_data svc; + + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sin4.sin_len = sizeof(sin4); +#endif + sin4.sin_addr.s_addr = INADDR_ANY; + + FOREACH_ELT (rpc_svc_data, i, svc) { + int s4; + + set_sa_port((struct sockaddr *)&sin4, htons(svc.port)); + s4 = setup_a_rpc_listener(data, (struct sockaddr *)&sin4); + if (s4 < 0) + return -1; + else { + if (add_rpc_listener_fd(data, &svc, s4) == NULL) + close(s4); + else { + FD_SET(s4, &sstate.rfds); + if (s4 >= sstate.max) + sstate.max = s4 + 1; + krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s", + s4, paddr((struct sockaddr *)&sin4)); + } + } + } + FD_ZERO(&rpc_listenfds); + rpc_listenfds = svc_fdset; + return 0; +} + +#if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && (defined(IP_PKTINFO) || defined(IPV6_PKTINFO)) +union pktinfo { +#ifdef HAVE_STRUCT_IN6_PKTINFO + struct in6_pktinfo pi6; +#endif +#ifdef HAVE_STRUCT_IN_PKTINFO + struct in_pktinfo pi4; +#endif + char c; +}; + +static int +setup_udp_port_1(struct socksetup *data, struct sockaddr *addr, + char *haddrbuf, int pktinfo); + +static void +setup_udp_pktinfo_ports(struct socksetup *data) +{ +#ifdef IP_PKTINFO + { + struct sockaddr_in sa; + int r; + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sa.sin_len = sizeof(sa); +#endif + r = setup_udp_port_1(data, (struct sockaddr *) &sa, "0.0.0.0", 4); + if (r == 0) + data->udp_flags &= ~UDP_DO_IPV4; + } +#endif +#ifdef IPV6_PKTINFO + { + struct sockaddr_in6 sa; + int r; + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; +#ifdef HAVE_SA_LEN + sa.sin6_len = sizeof(sa); +#endif + r = setup_udp_port_1(data, (struct sockaddr *) &sa, "::", 6); + if (r == 0) + data->udp_flags &= ~UDP_DO_IPV6; + } +#endif +} +#else /* no pktinfo compile-time support */ +static void +setup_udp_pktinfo_ports(struct socksetup *data) +{ +} +#endif + +static int +setup_udp_port_1(struct socksetup *data, struct sockaddr *addr, + char *haddrbuf, int pktinfo) +{ + int sock = -1, i, r; + u_short port; + + FOREACH_ELT (udp_port_data, i, port) { + sock = socket (addr->sa_family, SOCK_DGRAM, 0); + if (sock == -1) { + data->retval = errno; + com_err(data->prog, data->retval, + "Cannot create server socket for port %d address %s", + port, haddrbuf); + return 1; + } + set_cloexec_fd(sock); +#ifdef KRB5_USE_INET6 + if (addr->sa_family == AF_INET6) { +#ifdef IPV6_V6ONLY + if (setv6only(sock, 1)) + com_err(data->prog, errno, + "setsockopt(%d,IPV6_V6ONLY,1) failed", sock); + else + com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked", + sock); +#else + krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support"); +#endif /* IPV6_V6ONLY */ + } +#endif + set_sa_port(addr, htons(port)); + if (bind (sock, (struct sockaddr *)addr, socklen (addr)) == -1) { + data->retval = errno; + com_err(data->prog, data->retval, + "Cannot bind server socket to port %d address %s", + port, haddrbuf); + close(sock); + return 1; + } +#if !(defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && (defined(IP_PKTINFO) || defined(IPV6_PKTINFO))) + assert(pktinfo == 0); +#endif + if (pktinfo) { + r = set_pktinfo(sock, addr->sa_family); + if (r) { + com_err(data->prog, r, + "Cannot request packet info for udp socket address %s port %d", + haddrbuf, port); + close(sock); + return 1; + } + } + krb5_klog_syslog (LOG_INFO, "listening on fd %d: udp %s%s", sock, + paddr((struct sockaddr *)addr), + pktinfo ? " (pktinfo)" : ""); + if (add_udp_fd (data, sock, pktinfo) == 0) { + close(sock); + return 1; + } + FD_SET (sock, &sstate.rfds); + if (sock >= sstate.max) + sstate.max = sock + 1; + } + return 0; +} + +static int +setup_udp_port(void *P_data, struct sockaddr *addr) +{ + struct socksetup *data = P_data; + char haddrbuf[NI_MAXHOST]; + int err; + + if (addr->sa_family == AF_INET && !(data->udp_flags & UDP_DO_IPV4)) + return 0; +#ifdef AF_INET6 + if (addr->sa_family == AF_INET6 && !(data->udp_flags & UDP_DO_IPV6)) + return 0; +#endif + err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf), + 0, 0, NI_NUMERICHOST); + if (err) + strlcpy(haddrbuf, "<unprintable>", sizeof(haddrbuf)); + + switch (addr->sa_family) { + case AF_INET: + break; +#ifdef AF_INET6 + case AF_INET6: +#ifdef KRB5_USE_INET6 + break; +#else + { + static int first = 1; + if (first) { + krb5_klog_syslog (LOG_INFO, "skipping local ipv6 addresses"); + first = 0; + } + return 0; + } +#endif +#endif +#ifdef AF_LINK /* some BSD systems, AIX */ + case AF_LINK: + return 0; +#endif +#ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */ + case AF_DLI: + return 0; +#endif +#ifdef AF_APPLETALK + case AF_APPLETALK: + return 0; +#endif + default: + krb5_klog_syslog (LOG_INFO, + "skipping unrecognized local address family %d", + addr->sa_family); + return 0; + } + return setup_udp_port_1(data, addr, haddrbuf, 0); +} + +#if 1 +static void klog_handler(const void *data, size_t len) +{ + static char buf[BUFSIZ]; + static int bufoffset; + void *p; + +#define flush_buf() \ + (bufoffset \ + ? (((buf[0] == 0 || buf[0] == '\n') \ + ? (fork()==0?abort():(void)0) \ + : (void)0), \ + krb5_klog_syslog(LOG_INFO, "%s", buf), \ + memset(buf, 0, sizeof(buf)), \ + bufoffset = 0) \ + : 0) + + p = memchr(data, 0, len); + if (p) + len = (const char *)p - (const char *)data; +scan_for_newlines: + if (len == 0) + return; + p = memchr(data, '\n', len); + if (p) { + if (p != data) + klog_handler(data, (size_t)((const char *)p - (const char *)data)); + flush_buf(); + len -= ((const char *)p - (const char *)data) + 1; + data = 1 + (const char *)p; + goto scan_for_newlines; + } else if (len > sizeof(buf) - 1 || len + bufoffset > sizeof(buf) - 1) { + size_t x = sizeof(buf) - len - 1; + klog_handler(data, x); + flush_buf(); + len -= x; + data = (const char *)data + x; + goto scan_for_newlines; + } else { + memcpy(buf + bufoffset, data, len); + bufoffset += len; + } +} +#endif + +static int network_reconfiguration_needed = 0; + +#ifdef HAVE_STRUCT_RT_MSGHDR +#include <net/route.h> + +static char *rtm_type_name(int type) +{ + switch (type) { + case RTM_ADD: return "RTM_ADD"; + case RTM_DELETE: return "RTM_DELETE"; + case RTM_NEWADDR: return "RTM_NEWADDR"; + case RTM_DELADDR: return "RTM_DELADDR"; + case RTM_IFINFO: return "RTM_IFINFO"; + case RTM_OLDADD: return "RTM_OLDADD"; + case RTM_OLDDEL: return "RTM_OLDDEL"; + case RTM_RESOLVE: return "RTM_RESOLVE"; +#ifdef RTM_NEWMADDR + case RTM_NEWMADDR: return "RTM_NEWMADDR"; + case RTM_DELMADDR: return "RTM_DELMADDR"; +#endif + case RTM_MISS: return "RTM_MISS"; + case RTM_REDIRECT: return "RTM_REDIRECT"; + case RTM_LOSING: return "RTM_LOSING"; + case RTM_GET: return "RTM_GET"; + default: return "?"; + } +} + +static void process_routing_update(void *handle, struct connection *conn, + const char *prog, int selflags) +{ + int n_read; + struct rt_msghdr rtm; + + krb5_klog_syslog(LOG_INFO, "routing socket readable"); + while ((n_read = read(conn->fd, &rtm, sizeof(rtm))) > 0) { + if (n_read < sizeof(rtm)) { + /* Quick hack to figure out if the interesting + fields are present in a short read. + + A short read seems to be normal for some message types. + Only complain if we don't have the critical initial + header fields. */ +#define RS(FIELD) (offsetof(struct rt_msghdr, FIELD) + sizeof(rtm.FIELD)) + if (n_read < RS(rtm_type) || + n_read < RS(rtm_version) || + n_read < RS(rtm_msglen)) { + krb5_klog_syslog(LOG_ERR, + "short read (%d/%d) from routing socket", + n_read, (int) sizeof(rtm)); + return; + } + } + krb5_klog_syslog(LOG_INFO, + "got routing msg type %d(%s) v%d", + rtm.rtm_type, rtm_type_name(rtm.rtm_type), + rtm.rtm_version); + if (rtm.rtm_msglen > sizeof(rtm)) { + /* It appears we get a partial message and the rest is + thrown away? */ + } else if (rtm.rtm_msglen != n_read) { + krb5_klog_syslog(LOG_ERR, + "read %d from routing socket but msglen is %d", + n_read, rtm.rtm_msglen); + } + switch (rtm.rtm_type) { + case RTM_ADD: + case RTM_DELETE: + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_IFINFO: + case RTM_OLDADD: + case RTM_OLDDEL: + krb5_klog_syslog(LOG_INFO, "reconfiguration needed"); + network_reconfiguration_needed = 1; + break; + case RTM_RESOLVE: +#ifdef RTM_NEWMADDR + case RTM_NEWMADDR: + case RTM_DELMADDR: +#endif + case RTM_MISS: + case RTM_REDIRECT: + case RTM_LOSING: + case RTM_GET: + /* Not interesting. */ + krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting"); + break; + default: + krb5_klog_syslog(LOG_INFO, "unhandled routing message type, will reconfigure just for the fun of it"); + network_reconfiguration_needed = 1; + break; + } + } +} + +static void +setup_routing_socket(struct socksetup *data) +{ + int sock = socket(PF_ROUTE, SOCK_RAW, 0); + if (sock < 0) { + int e = errno; + krb5_klog_syslog(LOG_INFO, "couldn't set up routing socket: %s", + strerror(e)); + } else { + krb5_klog_syslog(LOG_INFO, "routing socket is fd %d", sock); + add_fd(data, sock, CONN_ROUTING, process_routing_update); + setnbio(sock); + FD_SET(sock, &sstate.rfds); + } +} +#endif + +/* XXX */ +extern int krb5int_debug_sendto_kdc; +extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t); + +krb5_error_code +setup_network(void *handle, const char *prog) +{ + struct socksetup setup_data; + krb5_error_code retval; + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + + FD_ZERO(&sstate.rfds); + FD_ZERO(&sstate.wfds); + FD_ZERO(&sstate.xfds); + sstate.max = 0; + +/* krb5int_debug_sendto_kdc = 1; */ + krb5int_sendtokdc_debug_handler = klog_handler; + + retval = add_udp_port(server_handle->params.kpasswd_port); + if (retval) + return retval; + + retval = add_tcp_port(server_handle->params.kpasswd_port); + if (retval) + return retval; + + retval = add_rpc_service(server_handle->params.kadmind_port, + KADM, KADMVERS, + kadm_1); + if (retval) + return retval; + +#ifndef DISABLE_IPROP + if (server_handle->params.iprop_enabled) { + retval = add_rpc_service(server_handle->params.iprop_port, + KRB5_IPROP_PROG, KRB5_IPROP_VERS, + krb5_iprop_prog_1); + if (retval) + return retval; + } +#endif /* DISABLE_IPROP */ + + setup_data.prog = prog; + setup_data.retval = 0; + krb5_klog_syslog (LOG_INFO, "setting up network..."); +#ifdef HAVE_STRUCT_RT_MSGHDR + setup_routing_socket(&setup_data); +#endif + /* To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO, + so we might need only one UDP socket; fall back to binding + sockets on each address only if IPV6_PKTINFO isn't + supported. */ + setup_data.udp_flags = UDP_DO_IPV4 | UDP_DO_IPV6; + setup_udp_pktinfo_ports(&setup_data); + if (setup_data.udp_flags) { + if (foreach_localaddr (&setup_data, setup_udp_port, 0, 0)) { + return setup_data.retval; + } + } + setup_tcp_listener_ports(&setup_data); + setup_rpc_listener_ports(&setup_data); + krb5_klog_syslog (LOG_INFO, "set up %d sockets", n_sockets); + if (n_sockets == 0) { + com_err(prog, 0, "no sockets set up?"); + exit (1); + } + + return 0; +} + +static void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET: + faddr->address->addrtype = ADDRTYPE_INET; + faddr->address->length = 4; + faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr; + faddr->port = ntohs(sa2sin(sa)->sin_port); + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) { + faddr->address->addrtype = ADDRTYPE_INET; + faddr->address->length = 4; + faddr->address->contents = 12 + (krb5_octet *) &sa2sin6(sa)->sin6_addr; + } else { + faddr->address->addrtype = ADDRTYPE_INET6; + faddr->address->length = 16; + faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr; + } + faddr->port = ntohs(sa2sin6(sa)->sin6_port); + break; +#endif + default: + faddr->address->addrtype = -1; + faddr->address->length = 0; + faddr->address->contents = 0; + faddr->port = 0; + break; + } +} + +static int +recv_from_to(int s, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen, + struct sockaddr *to, socklen_t *tolen) +{ +#if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE) + if (to && tolen) + *tolen = 0; + return recvfrom(s, buf, len, flags, from, fromlen); +#else + int r; + struct iovec iov; + char cmsg[CMSG_SPACE(sizeof(union pktinfo))]; + struct cmsghdr *cmsgptr; + struct msghdr msg; + + if (!to || !tolen) + return recvfrom(s, buf, len, flags, from, fromlen); + + iov.iov_base = buf; + iov.iov_len = len; + memset(&msg, 0, sizeof(msg)); + msg.msg_name = from; + msg.msg_namelen = *fromlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg; + msg.msg_controllen = sizeof(cmsg); + + r = recvmsg(s, &msg, flags); + if (r < 0) + return r; + *fromlen = msg.msg_namelen; + + /* On Darwin (and presumably all *BSD with KAME stacks), + CMSG_FIRSTHDR doesn't check for a non-zero controllen. RFC + 3542 recommends making this check, even though the (new) spec + for CMSG_FIRSTHDR says it's supposed to do the check. */ + if (msg.msg_controllen) { + cmsgptr = CMSG_FIRSTHDR(&msg); + while (cmsgptr) { +#ifdef IP_PKTINFO + if (cmsgptr->cmsg_level == IPPROTO_IP + && cmsgptr->cmsg_type == IP_PKTINFO + && *tolen >= sizeof(struct sockaddr_in)) { + struct in_pktinfo *pktinfo; + memset(to, 0, sizeof(struct sockaddr_in)); + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsgptr); + ((struct sockaddr_in *)to)->sin_addr = pktinfo->ipi_addr; + ((struct sockaddr_in *)to)->sin_family = AF_INET; + *tolen = sizeof(struct sockaddr_in); + return r; + } +#endif +#if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO)&& defined(HAVE_STRUCT_IN6_PKTINFO) + if (cmsgptr->cmsg_level == IPPROTO_IPV6 + && cmsgptr->cmsg_type == IPV6_PKTINFO + && *tolen >= sizeof(struct sockaddr_in6)) { + struct in6_pktinfo *pktinfo; + memset(to, 0, sizeof(struct sockaddr_in6)); + pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); + ((struct sockaddr_in6 *)to)->sin6_addr = pktinfo->ipi6_addr; + ((struct sockaddr_in6 *)to)->sin6_family = AF_INET6; + *tolen = sizeof(struct sockaddr_in6); + return r; + } +#endif + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr); + } + } + /* No info about destination addr was available. */ + *tolen = 0; + return r; +#endif +} + +static int +send_to_from(int s, void *buf, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen, + const struct sockaddr *from, socklen_t fromlen) +{ +#if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE) + return sendto(s, buf, len, flags, to, tolen); +#else + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsgptr; + char cbuf[CMSG_SPACE(sizeof(union pktinfo))]; + + if (from == 0 || fromlen == 0 || from->sa_family != to->sa_family) { + use_sendto: + return sendto(s, buf, len, flags, to, tolen); + } + + iov.iov_base = buf; + iov.iov_len = len; + /* Truncation? */ + if (iov.iov_len != len) + return EINVAL; + memset(cbuf, 0, sizeof(cbuf)); + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (void *) to; + msg.msg_namelen = tolen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cbuf; + /* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL + on Linux. */ + msg.msg_controllen = sizeof(cbuf); + cmsgptr = CMSG_FIRSTHDR(&msg); + msg.msg_controllen = 0; + + switch (from->sa_family) { +#if defined(IP_PKTINFO) + case AF_INET: + if (fromlen != sizeof(struct sockaddr_in)) + goto use_sendto; + cmsgptr->cmsg_level = IPPROTO_IP; + cmsgptr->cmsg_type = IP_PKTINFO; + cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + { + struct in_pktinfo *p = (struct in_pktinfo *)CMSG_DATA(cmsgptr); + const struct sockaddr_in *from4 = (const struct sockaddr_in *)from; + p->ipi_spec_dst = from4->sin_addr; + } + msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + break; +#endif +#if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) + case AF_INET6: + if (fromlen != sizeof(struct sockaddr_in6)) + goto use_sendto; + cmsgptr->cmsg_level = IPPROTO_IPV6; + cmsgptr->cmsg_type = IPV6_PKTINFO; + cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + { + struct in6_pktinfo *p = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); + const struct sockaddr_in6 *from6 = (const struct sockaddr_in6 *)from; + p->ipi6_addr = from6->sin6_addr; + } + msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + break; +#endif + default: + goto use_sendto; + } + return sendmsg(s, &msg, flags); +#endif +} + +/* Dispatch routine for set/change password */ +static krb5_error_code +dispatch(void *handle, + struct sockaddr *local_saddr, krb5_fulladdr *remote_faddr, + krb5_data *request, krb5_data **response) +{ + krb5_error_code ret; + krb5_keytab kt = NULL; + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + krb5_fulladdr local_faddr; + krb5_address **local_kaddrs = NULL, local_kaddr_buf; + + *response = NULL; + + if (local_saddr == NULL) { + ret = krb5_os_localaddr(server_handle->context, &local_kaddrs); + if (ret != 0) + goto cleanup; + + local_faddr.address = local_kaddrs[0]; + local_faddr.port = 0; + } else { + local_faddr.address = &local_kaddr_buf; + init_addr(&local_faddr, local_saddr); + } + + ret = krb5_kt_resolve(server_handle->context, "KDB:", &kt); + if (ret != 0) { + krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab %s", + krb5_get_error_message(server_handle->context, ret)); + goto cleanup; + } + + *response = (krb5_data *)malloc(sizeof(krb5_data)); + if (*response == NULL) { + ret = ENOMEM; + goto cleanup; + } + + ret = process_chpw_request(server_handle->context, + handle, + server_handle->params.realm, + kt, + &local_faddr, + remote_faddr, + request, + *response); + +cleanup: + if (local_kaddrs != NULL) + krb5_free_addresses(server_handle->context, local_kaddrs); + + krb5_kt_close(server_handle->context, kt); + + return ret; +} + +static void process_packet(void *handle, + struct connection *conn, const char *prog, + int selflags) +{ + int cc; + socklen_t saddr_len, daddr_len; + krb5_fulladdr faddr; + krb5_error_code retval; + struct sockaddr_storage saddr, daddr; + krb5_address addr; + krb5_data request; + krb5_data *response; + char pktbuf[MAX_DGRAM_SIZE]; + int port_fd = conn->fd; + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + + response = NULL; + saddr_len = sizeof(saddr); + daddr_len = sizeof(daddr); + cc = recv_from_to(port_fd, pktbuf, sizeof(pktbuf), 0, + (struct sockaddr *)&saddr, &saddr_len, + (struct sockaddr *)&daddr, &daddr_len); + if (cc == -1) { + if (errno != EINTR + /* This is how Linux indicates that a previous + transmission was refused, e.g., if the client timed out + before getting the response packet. */ + && errno != ECONNREFUSED + ) + com_err(prog, errno, "while receiving from network"); + return; + } + if (!cc) + return; /* zero-length packet? */ + +#if 0 + if (daddr_len > 0) { + char addrbuf[100]; + if (getnameinfo(ss2sa(&daddr), daddr_len, addrbuf, sizeof(addrbuf), + 0, 0, NI_NUMERICHOST)) + strlcpy(addrbuf, "?", sizeof(addrbuf)); + com_err(prog, 0, "pktinfo says local addr is %s", addrbuf); + } +#endif + + request.length = cc; + request.data = pktbuf; + faddr.address = &addr; + init_addr(&faddr, ss2sa(&saddr)); + /* this address is in net order */ + if ((retval = dispatch(handle, ss2sa(&daddr), &faddr, &request, &response))) { + com_err(prog, retval, "while dispatching (udp)"); + return; + } + if (response == NULL) + return; + cc = send_to_from(port_fd, response->data, (socklen_t) response->length, 0, + (struct sockaddr *)&saddr, saddr_len, + (struct sockaddr *)&daddr, daddr_len); + if (cc == -1) { + char addrbuf[46]; + krb5_free_data(server_handle->context, response); + if (inet_ntop(((struct sockaddr *)&saddr)->sa_family, + addr.contents, addrbuf, sizeof(addrbuf)) == 0) { + strlcpy(addrbuf, "?", sizeof(addrbuf)); + } + com_err(prog, errno, "while sending reply to %s/%d", + addrbuf, faddr.port); + return; + } + if (cc != response->length) { + com_err(prog, 0, "short reply write %d vs %d\n", + response->length, cc); + } + krb5_free_data(server_handle->context, response); + return; +} + +static int tcp_or_rpc_data_counter; +static int max_tcp_or_rpc_data_connections = 45; + +static void kill_tcp_or_rpc_connection(void *, struct connection *, int isForcedClose); + +static int kill_lru_tcp_or_rpc_connection(void *handle, struct connection *newconn) +{ + struct connection *oldest_tcp = NULL; + struct connection *c; + int i, fd = -1; + + krb5_klog_syslog(LOG_INFO, "too many connections"); + + FOREACH_ELT (connections, i, c) { + if (c->type != CONN_TCP && c->type != CONN_RPC) + continue; + if (c == newconn) + continue; +#if 0 + krb5_klog_syslog(LOG_INFO, "fd %d started at %ld", c->fd, + c->u.tcp.start_time); +#endif + if (oldest_tcp == NULL + || oldest_tcp->u.tcp.start_time > c->u.tcp.start_time) + oldest_tcp = c; + } + if (oldest_tcp != NULL) { + krb5_klog_syslog(LOG_INFO, "dropping %s fd %d from %s", + c->type == CONN_RPC ? "rpc" : "tcp", + oldest_tcp->fd, oldest_tcp->u.tcp.addrbuf); + fd = oldest_tcp->fd; + kill_tcp_or_rpc_connection(handle, oldest_tcp, 1); + } + return fd; +} + +static void accept_tcp_connection(void *handle, + struct connection *conn, const char *prog, + int selflags) +{ + int s; + struct sockaddr_storage addr_s; + struct sockaddr *addr = (struct sockaddr *)&addr_s; + socklen_t addrlen = sizeof(addr_s); + struct socksetup sockdata; + struct connection *newconn; + char tmpbuf[10]; + + s = accept(conn->fd, addr, &addrlen); + if (s < 0) + return; + set_cloexec_fd(s); +#ifndef _WIN32 + if (s >= FD_SETSIZE) { + close(s); + return; + } +#endif + setnbio(s), setnolinger(s), setkeepalive(s); + + sockdata.prog = prog; + sockdata.retval = 0; + + newconn = add_tcp_data_fd(&sockdata, s); + if (newconn == NULL) + return; + + if (getnameinfo((struct sockaddr *)&addr_s, addrlen, + newconn->u.tcp.addrbuf, sizeof(newconn->u.tcp.addrbuf), + tmpbuf, sizeof(tmpbuf), + NI_NUMERICHOST | NI_NUMERICSERV)) + strlcpy(newconn->u.tcp.addrbuf, "???", sizeof(newconn->u.tcp.addrbuf)); + else { + char *p, *end; + p = newconn->u.tcp.addrbuf; + end = p + sizeof(newconn->u.tcp.addrbuf); + p += strlen(p); + if (end - p > 2 + strlen(tmpbuf)) { + *p++ = '.'; + strlcpy(p, tmpbuf, end - p); + } + } +#if 0 + krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s", + s, newconn->u.tcp.addrbuf); +#endif + + newconn->u.tcp.addr_s = addr_s; + newconn->u.tcp.addrlen = addrlen; + newconn->u.tcp.bufsiz = 1024 * 1024; + newconn->u.tcp.buffer = malloc(newconn->u.tcp.bufsiz); + newconn->u.tcp.start_time = time(0); + + if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections) + kill_lru_tcp_or_rpc_connection(handle, newconn); + + if (newconn->u.tcp.buffer == 0) { + com_err(prog, errno, "allocating buffer for new TCP session from %s", + newconn->u.tcp.addrbuf); + delete_fd(newconn); + close(s); + tcp_or_rpc_data_counter--; + return; + } + newconn->u.tcp.offset = 0; + newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr; + init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s)); + SG_SET(&newconn->u.tcp.sgbuf[0], newconn->u.tcp.lenbuf, 4); + SG_SET(&newconn->u.tcp.sgbuf[1], 0, 0); + + FD_SET(s, &sstate.rfds); + if (sstate.max <= s) + sstate.max = s + 1; +} + +static void +kill_tcp_or_rpc_connection(void *handle, struct connection *conn, int isForcedClose) +{ + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + + assert(conn->type == CONN_TCP || conn->type == CONN_RPC); + assert(conn->fd != -1); + + if (conn->u.tcp.response) + krb5_free_data(server_handle->context, conn->u.tcp.response); + if (conn->u.tcp.buffer) + free(conn->u.tcp.buffer); + FD_CLR(conn->fd, &sstate.rfds); + FD_CLR(conn->fd, &sstate.wfds); + if (sstate.max == conn->fd + 1) + while (sstate.max > 0 + && ! FD_ISSET(sstate.max-1, &sstate.rfds) + && ! FD_ISSET(sstate.max-1, &sstate.wfds) + /* && ! FD_ISSET(sstate.max-1, &sstate.xfds) */ + ) + sstate.max--; + + /* In the non-forced case, the RPC runtime will close the descriptor for us */ + if (conn->type == CONN_TCP || isForcedClose) { + close(conn->fd); + } + + /* For RPC connections, call into RPC runtime to flush out any internal state */ + if (conn->type == CONN_RPC && isForcedClose) { + fd_set fds; + + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + + svc_getreqset(&fds); + + if (FD_ISSET(conn->fd, &svc_fdset)) { + krb5_klog_syslog(LOG_ERR, + "descriptor %d closed but still in svc_fdset", conn->fd); + } + } + + conn->fd = -1; + delete_fd(conn); + tcp_or_rpc_data_counter--; +} + +static krb5_error_code +make_toolong_error (void *handle, krb5_data **out) +{ + krb5_error errpkt; + krb5_error_code retval; + krb5_data *scratch; + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + + retval = krb5_us_timeofday(server_handle->context, &errpkt.stime, &errpkt.susec); + if (retval) + return retval; + errpkt.error = KRB_ERR_FIELD_TOOLONG; + retval = krb5_build_principal(server_handle->context, &errpkt.server, + strlen(server_handle->params.realm), + server_handle->params.realm, + "kadmin", "changepw", NULL); + if (retval) + return retval; + errpkt.client = NULL; + errpkt.cusec = 0; + errpkt.ctime = 0; + errpkt.text.length = 0; + errpkt.text.data = 0; + errpkt.e_data.length = 0; + errpkt.e_data.data = 0; + scratch = malloc(sizeof(*scratch)); + if (scratch == NULL) + return ENOMEM; + retval = krb5_mk_error(server_handle->context, &errpkt, scratch); + if (retval) { + free(scratch); + return retval; + } + + *out = scratch; + return 0; +} + +static void +queue_tcp_outgoing_response(struct connection *conn) +{ + store_32_be(conn->u.tcp.response->length, conn->u.tcp.lenbuf); + SG_SET(&conn->u.tcp.sgbuf[1], conn->u.tcp.response->data, + conn->u.tcp.response->length); + conn->u.tcp.sgp = conn->u.tcp.sgbuf; + conn->u.tcp.sgnum = 2; + FD_SET(conn->fd, &sstate.wfds); +} + +static void +process_tcp_connection(void *handle, + struct connection *conn, const char *prog, int selflags) +{ + int isForcedClose = 1; /* not used now, but for completeness */ + + if (selflags & SSF_WRITE) { + ssize_t nwrote; + SOCKET_WRITEV_TEMP tmp; + + nwrote = SOCKET_WRITEV(conn->fd, conn->u.tcp.sgp, conn->u.tcp.sgnum, + tmp); + if (nwrote < 0) { + goto kill_tcp_connection; + } + if (nwrote == 0) { + /* eof */ + isForcedClose = 0; + goto kill_tcp_connection; + } + while (nwrote) { + sg_buf *sgp = conn->u.tcp.sgp; + if (nwrote < SG_LEN(sgp)) { + SG_ADVANCE(sgp, nwrote); + nwrote = 0; + } else { + nwrote -= SG_LEN(sgp); + conn->u.tcp.sgp++; + conn->u.tcp.sgnum--; + if (conn->u.tcp.sgnum == 0 && nwrote != 0) + abort(); + } + } + if (conn->u.tcp.sgnum == 0) { + /* finished sending */ + /* We should go back to reading, though if we sent a + FIELD_TOOLONG error in reply to a length with the high + bit set, RFC 4120 says we have to close the TCP + stream. */ + isForcedClose = 0; + goto kill_tcp_connection; + } + } else if (selflags & SSF_READ) { + /* Read message length and data into one big buffer, already + allocated at connect time. If we have a complete message, + we stop reading, so we should only be here if there is no + data in the buffer, or only an incomplete message. */ + size_t len; + ssize_t nread; + if (conn->u.tcp.offset < 4) { + /* msglen has not been computed */ + /* XXX Doing at least two reads here, letting the kernel + worry about buffering. It'll be faster when we add + code to manage the buffer here. */ + len = 4 - conn->u.tcp.offset; + nread = SOCKET_READ(conn->fd, + conn->u.tcp.buffer + conn->u.tcp.offset, len); + if (nread < 0) + /* error */ + goto kill_tcp_connection; + if (nread == 0) + /* eof */ + goto kill_tcp_connection; + conn->u.tcp.offset += nread; + if (conn->u.tcp.offset == 4) { + unsigned char *p = (unsigned char *)conn->u.tcp.buffer; + conn->u.tcp.msglen = load_32_be(p); + if (conn->u.tcp.msglen > conn->u.tcp.bufsiz - 4) { + krb5_error_code err; + /* message too big */ + krb5_klog_syslog(LOG_ERR, "TCP client %s wants %lu bytes, cap is %lu", + conn->u.tcp.addrbuf, (unsigned long) conn->u.tcp.msglen, + (unsigned long) conn->u.tcp.bufsiz - 4); + /* XXX Should return an error. */ + err = make_toolong_error (handle, &conn->u.tcp.response); + if (err) { + krb5_klog_syslog(LOG_ERR, + "error constructing KRB_ERR_FIELD_TOOLONG error! %s", + error_message(err)); + goto kill_tcp_connection; + } + goto have_response; + } + } + } else { + /* msglen known */ + krb5_data request; + krb5_error_code err; + struct sockaddr_storage local_saddr; + socklen_t local_saddrlen = sizeof(local_saddr); + struct sockaddr *local_saddrp = NULL; + + len = conn->u.tcp.msglen - (conn->u.tcp.offset - 4); + nread = SOCKET_READ(conn->fd, + conn->u.tcp.buffer + conn->u.tcp.offset, len); + if (nread < 0) + /* error */ + goto kill_tcp_connection; + if (nread == 0) + /* eof */ + goto kill_tcp_connection; + conn->u.tcp.offset += nread; + if (conn->u.tcp.offset < conn->u.tcp.msglen + 4) + return; + /* have a complete message, and exactly one message */ + request.length = conn->u.tcp.msglen; + request.data = conn->u.tcp.buffer + 4; + + if (getsockname(conn->fd, ss2sa(&local_saddr), &local_saddrlen) == 0) { + local_saddrp = ss2sa(&local_saddr); + } + + err = dispatch(handle, local_saddrp, &conn->u.tcp.faddr, + &request, &conn->u.tcp.response); + if (err) { + com_err(prog, err, "while dispatching (tcp)"); + goto kill_tcp_connection; + } + have_response: + queue_tcp_outgoing_response(conn); + FD_CLR(conn->fd, &sstate.rfds); + } + } else + abort(); + + return; + +kill_tcp_connection: + kill_tcp_or_rpc_connection(handle, conn, isForcedClose); +} + +static void service_conn(void *handle, + struct connection *conn, const char *prog, + int selflags) +{ + conn->service(handle, conn, prog, selflags); +} + +static int getcurtime(struct timeval *tvp) +{ +#ifdef _WIN32 + struct _timeb tb; + _ftime(&tb); + tvp->tv_sec = tb.time; + tvp->tv_usec = tb.millitm * 1000; + return 0; +#else + return gettimeofday(tvp, 0) ? errno : 0; +#endif +} + +krb5_error_code +listen_and_process(void *handle, const char *prog) +{ + int nfound; + /* This struct contains 3 fd_set objects; on some platforms, they + can be rather large. Making this static avoids putting all + that junk on the stack. */ + static struct select_state sout; + int i, sret, netchanged = 0; + krb5_error_code err; + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + + if (conns == (struct connection **) NULL) + return KDC5_NONET; + + while (!signal_request_exit) { + if (signal_request_hup) { + krb5_klog_reopen(server_handle->context); + reset_db(); + signal_request_hup = 0; + } +#ifdef PURIFY + if (signal_pure_report) { + purify_new_reports(); + signal_pure_report = 0; + } + if (signal_pure_clear) { + purify_clear_new_reports(); + signal_pure_clear = 0; + } +#endif /* PURIFY */ + if (network_reconfiguration_needed) { + krb5_klog_syslog(LOG_INFO, "network reconfiguration needed"); + /* It might be tidier to add a timer-callback interface to + the control loop here, but for this one use, it's not a + big deal. */ + err = getcurtime(&sstate.end_time); + if (err) { + com_err(prog, err, "while getting the time"); + continue; + } + sstate.end_time.tv_sec += 3; + netchanged = 1; + } else + sstate.end_time.tv_sec = sstate.end_time.tv_usec = 0; + + err = krb5int_cm_call_select(&sstate, &sout, &sret); + if (err) { + if (err != EINTR) + com_err(prog, err, "while selecting for network input(1)"); + continue; + } + if (sret == 0 && netchanged) { + network_reconfiguration_needed = 0; + closedown_network(handle, prog); + err = setup_network(handle, prog); + if (err) { + com_err(prog, err, "while reinitializing network"); + return err; + } + netchanged = 0; + } + if (sret == -1) { + if (errno != EINTR) + com_err(prog, errno, "while selecting for network input(2)"); + continue; + } + nfound = sret; + for (i=0; i<n_sockets && nfound > 0; i++) { + int sflags = 0; + if (conns[i]->fd < 0) + abort(); + if (FD_ISSET(conns[i]->fd, &sout.rfds)) + sflags |= SSF_READ, nfound--; + if (FD_ISSET(conns[i]->fd, &sout.wfds)) + sflags |= SSF_WRITE, nfound--; + if (sflags) + service_conn(handle, conns[i], prog, sflags); + } + } + krb5_klog_syslog(LOG_INFO, "shutdown signal received"); + return 0; +} + +krb5_error_code +closedown_network(void *handle, const char *prog) +{ + int i; + struct connection *conn; + + if (conns == (struct connection **) NULL) + return KDC5_NONET; + + FOREACH_ELT (connections, i, conn) { + if (conn->fd >= 0) { + krb5_klog_syslog(LOG_INFO, "closing down fd %d", conn->fd); + (void) close(conn->fd); + if (conn->type == CONN_RPC) { + fd_set fds; + + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + + svc_getreqset(&fds); + } + } + if (conn->type == CONN_RPC_LISTENER) { + if (conn->u.rpc.transp != NULL) + svc_destroy(conn->u.rpc.transp); + } + DEL (connections, i); + /* There may also be per-connection data in the tcp structure + (tcp.buffer, tcp.response) that we're not freeing here. + That should only happen if we quit with a connection in + progress. */ + free(conn); + } + FREE_SET_DATA(connections); + FREE_SET_DATA(udp_port_data); + FREE_SET_DATA(tcp_port_data); + FREE_SET_DATA(rpc_svc_data); + + return 0; +} + +static void accept_rpc_connection(void *handle, struct connection *conn, + const char *prog, int selflags) +{ + struct socksetup sockdata; + fd_set fds; + register int s; + + assert(selflags & SSF_READ); + + if ((selflags & SSF_READ) == 0) + return; + + sockdata.prog = prog; + sockdata.retval = 0; + + /* + * Service the woken RPC listener descriptor. + */ + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + + svc_getreqset(&fds); + + /* + * Scan svc_fdset for any new connections. + */ + for (s = 0; s < FD_SETSIZE; s++) { + /* sstate.rfds |= svc_fdset & ~(rpc_listenfds | sstate.rfds) */ + if (FD_ISSET(s, &svc_fdset) + && !FD_ISSET(s, &rpc_listenfds) + && !FD_ISSET(s, &sstate.rfds)) + { + struct connection *newconn; + struct sockaddr_storage addr_s; + struct sockaddr *addr = (struct sockaddr *)&addr_s; + socklen_t addrlen = sizeof(addr_s); + char tmpbuf[10]; + + newconn = add_rpc_data_fd(&sockdata, s); + if (newconn == NULL) + continue; + + set_cloexec_fd(s); +#if 0 + setnbio(s), setnolinger(s), setkeepalive(s); +#endif + + if (getpeername(s, addr, &addrlen) || + getnameinfo(addr, addrlen, + newconn->u.tcp.addrbuf, sizeof(newconn->u.tcp.addrbuf), + tmpbuf, sizeof(tmpbuf), + NI_NUMERICHOST | NI_NUMERICSERV)) + strlcpy(newconn->u.tcp.addrbuf, "???", sizeof(newconn->u.tcp.addrbuf)); + else { + char *p, *end; + p = newconn->u.tcp.addrbuf; + end = p + sizeof(newconn->u.tcp.addrbuf); + p += strlen(p); + if (end - p > 2 + strlen(tmpbuf)) { + *p++ = '.'; + strlcpy(p, tmpbuf, end - p); + } + } +#if 0 + krb5_klog_syslog(LOG_INFO, "accepted RPC connection on socket %d from %s", + s, newconn->u.tcp.addrbuf); +#endif + + newconn->u.tcp.addr_s = addr_s; + newconn->u.tcp.addrlen = addrlen; + newconn->u.tcp.start_time = time(0); + + if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections) + kill_lru_tcp_or_rpc_connection(handle, newconn); + + newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr; + init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s)); + + FD_SET(s, &sstate.rfds); + if (sstate.max <= s) + sstate.max = s + 1; + } + } +} + +static void process_rpc_connection(void *handle, struct connection *conn, + const char *prog, int selflags) +{ + fd_set fds; + + assert(selflags & SSF_READ); + + if ((selflags & SSF_READ) == 0) + return; + + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + + svc_getreqset(&fds); + + if (!FD_ISSET(conn->fd, &svc_fdset)) + kill_tcp_or_rpc_connection(handle, conn, 0); +} + +#endif /* INET */ diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c index 8b00172..573a2c0 100644 --- a/src/kadmin/server/ovsec_kadmd.c +++ b/src/kadmin/server/ovsec_kadmd.c @@ -77,7 +77,6 @@ void request_exit(int); void request_hup(int); void reset_db(void); void sig_pipe(int); -void kadm_svc_run(kadm5_config_params *params); #ifdef POSIX_SIGNALS static struct sigaction s_action; @@ -208,15 +207,12 @@ int nofork = 0; int main(int argc, char *argv[]) { - register SVCXPRT *transp, *iproptransp; extern char *optarg; extern int optind, opterr; int ret, oldnames = 0; OM_uint32 OMret, major_status, minor_status; char *whoami; gss_buffer_desc in_buf; - struct sockaddr_in addr; - int s; auth_gssapi_name names[4]; gss_buffer_desc gssbuf; gss_OID nt_krb5_name_oid; @@ -224,8 +220,8 @@ int main(int argc, char *argv[]) char **db_args = NULL; int db_args_size = 0; char *errmsg; + int i; - char *kiprop_name = NULL; /* iprop svc name */ kdb_log_context *log_ctx; setvbuf(stderr, NULL, _IONBF, 0); @@ -352,238 +348,17 @@ int main(int argc, char *argv[]) exit(1); } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(params.kadmind_port); - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - const char *e_txt; - ret = SOCKET_ERRNO; - e_txt = krb5_get_error_message (context, ret); - krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s", - e_txt); - fprintf(stderr, "Cannot create TCP socket: %s", - e_txt); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - set_cloexec_fd(s); - - if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - const char *e_txt; - ret = SOCKET_ERRNO; - e_txt = krb5_get_error_message (context, ret); - krb5_klog_syslog(LOG_ERR, - "cannot create simple chpw socket: %s", - e_txt); - fprintf(stderr, "Cannot create simple chpw socket: %s", - e_txt); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - set_cloexec_fd(schpw); - -#ifndef DISABLE_IPROP - if ((ipropfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - const char *e_txt; - ret = SOCKET_ERRNO; - e_txt = krb5_get_error_message (context, ret); - krb5_klog_syslog(LOG_ERR, - "cannot create iprop listening socket: %s", - e_txt); - fprintf(stderr, "cannot create iprop listening socket: %s", - e_txt); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - set_cloexec_fd(ipropfd); -#endif - -#ifdef SO_REUSEADDR - /* the old admin server turned on SO_REUSEADDR for non-default - port numbers. this was necessary, on solaris, for the tests - to work. jhawk argues that the debug and production modes - should be the same. I think I agree, so I'm always going to set - SO_REUSEADDR. The other option is to have the unit tests wait - until the port is useable, or use a different port each time. - --marc */ - - { - int allowed; - - allowed = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (char *) &allowed, sizeof(allowed)) < 0 || - setsockopt(schpw, SOL_SOCKET, SO_REUSEADDR, - (char *) &allowed, sizeof(allowed)) < 0 -#ifndef DISABLE_IPROP - || setsockopt(ipropfd, SOL_SOCKET, SO_REUSEADDR, - (char *) &allowed, sizeof(allowed)) < 0 -#endif - ) { - const char *e_txt; - ret = SOCKET_ERRNO; - e_txt = krb5_get_error_message (context, ret); - krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s", - e_txt); - fprintf(stderr, "Cannot set SO_REUSEADDR: %s", e_txt); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - } -#endif /* SO_REUSEADDR */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(params.kadmind_port); - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - int oerrno = errno; - const char *e_txt = krb5_get_error_message (context, errno); - fprintf(stderr, "%s: Cannot bind socket.\n", whoami); - fprintf(stderr, "bind: %s\n", e_txt); - errno = oerrno; - krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %s", e_txt); - if(oerrno == EADDRINUSE) { - char *w = strrchr(whoami, '/'); - if (w) { - w++; - } - else { - w = whoami; - } - fprintf(stderr, -"This probably means that another %s process is already\n" -"running, or that another program is using the server port (number %d)\n" -"after being assigned it by the RPC portmap daemon. If another\n" -"%s is already running, you should kill it before\n" -"restarting the server. If, on the other hand, another program is\n" -"using the server port, you should kill it before running\n" -"%s, and ensure that the conflict does not occur in the\n" -"future by making sure that %s is started on reboot\n" - "before portmap.\n", w, ntohs(addr.sin_port), w, w, w); - krb5_klog_syslog(LOG_ERR, "Check for already-running %s or for " - "another process using port %d", w, - htons(addr.sin_port)); - } + if ((ret = setup_network(global_server_handle, whoami))) { + const char *e_txt = krb5_get_error_message (context, ret); + krb5_klog_syslog(LOG_ERR, "%s: %s while initializing network, aborting", + whoami, e_txt); + fprintf(stderr, "%s: %s while initializing network, aborting\n", + whoami, e_txt); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - /* XXX */ - addr.sin_port = htons(params.kpasswd_port); - - if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - char portbuf[32]; - int oerrno = errno; - const char *e_txt = krb5_get_error_message (context, errno); - fprintf(stderr, "%s: Cannot bind socket.\n", whoami); - fprintf(stderr, "bind: %s\n", e_txt); - errno = oerrno; - snprintf(portbuf, sizeof(portbuf), "%d", ntohs(addr.sin_port)); - krb5_klog_syslog(LOG_ERR, "cannot bind simple chpw socket: %s", - e_txt); - if(oerrno == EADDRINUSE) { - char *w = strrchr(whoami, '/'); - if (w) { - w++; - } - else { - w = whoami; - } - fprintf(stderr, -"This probably means that another %s process is already\n" -"running, or that another program is using the server port (number %d).\n" -"If another %s is already running, you should kill it before\n" -"restarting the server.\n", - w, ntohs(addr.sin_port), w); - } - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - -#ifndef DISABLE_IPROP - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(params.iprop_port); - if (bind(ipropfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - char portbuf[32]; - int oerrno = errno; - const char *e_txt = krb5_get_error_message (context, errno); - fprintf(stderr, "%s: Cannot bind socket.\n", whoami); - fprintf(stderr, "bind: %s\n", e_txt); - errno = oerrno; - snprintf(portbuf, sizeof(portbuf), "%d", ntohs(addr.sin_port)); - krb5_klog_syslog(LOG_ERR, "cannot bind iprop socket: %s", - e_txt); - if(oerrno == EADDRINUSE) { - char *w = strrchr(whoami, '/'); - if (w) { - w++; - } - else { - w = whoami; - } - fprintf(stderr, -"This probably means that another %s process is already\n" -"running, or that another program is using the server port (number %d).\n" -"If another %s is already running, you should kill it before\n" -"restarting the server.\n", - w, ntohs(addr.sin_port), w); - } - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } -#endif - - transp = svctcp_create(s, 0, 0); - if(transp == NULL) { - fprintf(stderr, "%s: Cannot create RPC service.\n", whoami); - krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m"); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) { - fprintf(stderr, "%s: Cannot register RPC service.\n", whoami); - krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, failing."); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - -#ifndef DISABLE_IPROP - iproptransp = svctcp_create(ipropfd, 0, 0); - if (iproptransp == NULL) { - fprintf(stderr, "%s: Cannot create RPC service.\n", whoami); - krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m"); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - if (!svc_register(iproptransp, KRB5_IPROP_PROG, KRB5_IPROP_VERS, krb5_iprop_prog_1, IPPROTO_TCP)) { - fprintf(stderr, "%s: Cannot register RPC service.\n", whoami); - krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, continuing."); -#if 0 - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); -#endif - } -#endif - names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm); names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm); names[2].name = build_princ_name(OVSEC_KADM_ADMIN_SERVICE, params.realm); @@ -821,13 +596,13 @@ kterr: if (nofork) fprintf(stderr, "%s: starting...\n", whoami); - kadm_svc_run(¶ms); + listen_and_process(global_server_handle, whoami); krb5_klog_syslog(LOG_INFO, "finished, exiting"); /* Clean up memory, etc */ svcauth_gssapi_unset_names(); kadm5_destroy(global_server_handle); - close(s); + closedown_network(global_server_handle, whoami); kadm5int_acl_finish(context, 0); if(gss_changepw_name) { (void) gss_release_name(&OMret, &gss_changepw_name); @@ -835,9 +610,9 @@ kterr: if(gss_oldchangepw_name) { (void) gss_release_name(&OMret, &gss_oldchangepw_name); } - for(s = 0 ; s < 4; s++) { - if (names[s].name) { - free(names[s].name); + for(i = 0 ; i < 4; i++) { + if (names[i].name) { + free(names[i].name); } } @@ -899,68 +674,6 @@ void setup_signal_handlers(iprop_role iproprole) { #endif /* POSIX_SIGNALS */ } -/* - * Function: kadm_svc_run - * - * Purpose: modified version of sunrpc svc_run. - * which closes the database every TIMEOUT seconds. - * - * Arguments: - * Requires: - * Effects: - * Modifies: - */ - -void kadm_svc_run(params) -kadm5_config_params *params; -{ - fd_set rfd; - struct timeval timeout; - - while(signal_request_exit == 0) { - if (signal_request_hup) { - reset_db(); - krb5_klog_reopen(context); - signal_request_hup = 0; - } -#ifdef PURIFY - if (signal_pure_report) /* check to see if a report */ - /* should be dumped... */ - { - purify_new_reports(); - signal_pure_report = 0; - } - if (signal_pure_clear) /* ...before checking whether */ - /* the info should be cleared. */ - { - purify_clear_new_reports(); - signal_pure_clear = 0; - } -#endif /* PURIFY */ - timeout.tv_sec = TIMEOUT; - timeout.tv_usec = 0; - rfd = svc_fdset; - FD_SET(schpw, &rfd); -#define max(a, b) (((a) > (b)) ? (a) : (b)) - switch(select(max(schpw, svc_maxfd) + 1, - (fd_set *) &rfd, NULL, NULL, &timeout)) { - case -1: - if(errno == EINTR) - continue; - perror("select"); - return; - case 0: - reset_db(); - break; - default: - if (FD_ISSET(schpw, &rfd)) - do_schpw(schpw, params); - else - svc_getreqset(&rfd); - } - } -} - #ifdef PURIFY /* * Function: request_pure_report @@ -1332,99 +1045,3 @@ void log_badauth_display_status_1(char *m, OM_uint32 code, int type, } } -void do_schpw(int s1, kadm5_config_params *params) -{ - krb5_error_code ret; - /* XXX buffer = ethernet mtu */ - char req[1500]; - int len; - struct sockaddr_in from; - socklen_t fromlen; - krb5_keytab kt; - krb5_data reqdata, repdata; - int s2; - - fromlen = sizeof(from); - if ((len = recvfrom(s1, req, sizeof(req), 0, (struct sockaddr *)&from, - &fromlen)) < 0) { - krb5_klog_syslog(LOG_ERR, "chpw: Couldn't receive request: %s", - krb5_get_error_message (context, errno)); - return; - } - - if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) { - krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab %s", - krb5_get_error_message (context, ret)); - return; - } - - reqdata.length = len; - reqdata.data = req; - - /* this is really obscure. s1 is used for all communications. it - is left unconnected in case the server is multihomed and routes - are asymmetric. s2 is connected to resolve routes and get - addresses. this is the *only* way to get proper addresses for - multihomed hosts if routing is asymmetric. - - A related problem in the server, but not the client, is that - many os's have no way to disconnect a connected udp socket, so - the s2 socket needs to be closed and recreated for each - request. The s1 socket must not be closed, or else queued - requests will be lost. - - A "naive" client implementation (one socket, no connect, - hostname resolution to get the local ip addr) will work and - interoperate if the client is single-homed. */ - - if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - const char *errmsg = krb5_get_error_message (context, errno); - krb5_klog_syslog(LOG_ERR, "cannot create connecting socket: %s", - errmsg); - fprintf(stderr, "Cannot create connecting socket: %s", - errmsg); - svcauth_gssapi_unset_names(); - kadm5_destroy(global_server_handle); - krb5_klog_close(context); - exit(1); - } - set_cloexec_fd(s2); - - if (connect(s2, (struct sockaddr *) &from, sizeof(from)) < 0) { - krb5_klog_syslog(LOG_ERR, "chpw: Couldn't connect to client: %s", - krb5_get_error_message (context, errno)); - goto cleanup; - } - - if ((ret = process_chpw_request(context, global_server_handle, - params->realm, s2, kt, &from, - &reqdata, &repdata))) { - krb5_klog_syslog(LOG_ERR, "chpw: Error processing request: %s", - krb5_get_error_message (context, ret)); - } - - close(s2); - - if (repdata.length == 0) { - /* just return. This means something really bad happened */ - goto cleanup; - } - - len = sendto(s1, repdata.data, (int) repdata.length, 0, - (struct sockaddr *) &from, sizeof(from)); - - if (len < (int) repdata.length) { - krb5_xfree(repdata.data); - - krb5_klog_syslog(LOG_ERR, "chpw: Error sending reply: %s", - krb5_get_error_message (context, errno)); - goto cleanup; - } - - krb5_xfree(repdata.data); - -cleanup: - krb5_kt_close(context, kt); - - return; -} diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c index e8a6896..53f2e59 100644 --- a/src/kadmin/server/schpw.c +++ b/src/kadmin/server/schpw.c @@ -11,37 +11,40 @@ #define GETSOCKNAME_ARG3_TYPE int #endif +#define RFC3244_VERSION 0xff80 + krb5_error_code -process_chpw_request(context, server_handle, realm, s, keytab, sockin, - req, rep) +process_chpw_request(context, server_handle, realm, keytab, + local_faddr, remote_faddr, req, rep) krb5_context context; void *server_handle; char *realm; - int s; krb5_keytab keytab; - struct sockaddr_in *sockin; + krb5_fulladdr *local_faddr; + krb5_fulladdr *remote_faddr; krb5_data *req; krb5_data *rep; { krb5_error_code ret; char *ptr; int plen, vno; - krb5_address local_kaddr, remote_kaddr; - int allocated_mem = 0; krb5_data ap_req, ap_rep; krb5_auth_context auth_context; krb5_principal changepw; + krb5_principal client, target = NULL; krb5_ticket *ticket; krb5_data cipher, clear; - struct sockaddr local_addr, remote_addr; - GETSOCKNAME_ARG3_TYPE addrlen; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; - char *clientstr; + char *clientstr = NULL, *targetstr = NULL; size_t clen; char *cdots; + struct sockaddr_storage ss; + socklen_t salen; + char addrbuf[100]; + krb5_address *addr = remote_faddr->address; ret = 0; rep->length = 0; @@ -77,7 +80,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, vno = (*ptr++ & 0xff) ; vno = (vno<<8) | (*ptr++ & 0xff); - if (vno != 1) { + if (vno != 1 && vno != RFC3244_VERSION) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_BAD_VERSION; snprintf(strresult, sizeof(strresult), @@ -139,61 +142,6 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, goto chpwfail; } - /* set up address info */ - - addrlen = sizeof(local_addr); - - if (getsockname(s, &local_addr, &addrlen) < 0) { - ret = errno; - numresult = KRB5_KPASSWD_HARDERROR; - strlcpy(strresult, "Failed getting server internet address", - sizeof(strresult)); - goto chpwfail; - } - - /* some brain-dead OS's don't return useful information from - * the getsockname call. Namely, windows and solaris. */ - - if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) { - local_kaddr.addrtype = ADDRTYPE_INET; - local_kaddr.length = - sizeof(((struct sockaddr_in *) &local_addr)->sin_addr); - local_kaddr.contents = - (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr); - } else { - krb5_address **addrs; - - krb5_os_localaddr(context, &addrs); - local_kaddr.magic = addrs[0]->magic; - local_kaddr.addrtype = addrs[0]->addrtype; - local_kaddr.length = addrs[0]->length; - local_kaddr.contents = malloc(addrs[0]->length); - memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); - allocated_mem++; - - krb5_free_addresses(context, addrs); - } - - addrlen = sizeof(remote_addr); - - if (getpeername(s, &remote_addr, &addrlen) < 0) { - ret = errno; - numresult = KRB5_KPASSWD_HARDERROR; - strlcpy(strresult, "Failed getting client internet address", - sizeof(strresult)); - goto chpwfail; - } - - remote_kaddr.addrtype = ADDRTYPE_INET; - remote_kaddr.length = - sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr); - remote_kaddr.contents = - (krb5_octet *) &(((struct sockaddr_in *) &remote_addr)->sin_addr); - - remote_kaddr.addrtype = ADDRTYPE_INET; - remote_kaddr.length = sizeof(sockin->sin_addr); - remote_kaddr.contents = (krb5_octet *) &sockin->sin_addr; - /* mk_priv requires that the local address be set. getsockname is used for this. rd_priv requires that the remote address be set. recvfrom is used for this. If @@ -209,7 +157,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, is specified. Are we having fun yet? */ ret = krb5_auth_con_setaddrs(context, auth_context, NULL, - &remote_kaddr); + remote_faddr->address); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed storing client internet address", @@ -217,15 +165,6 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, goto chpwfail; } - /* verify that this is an AS_REQ ticket */ - - if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) { - numresult = KRB5_KPASSWD_AUTHERROR; - strlcpy(strresult, "Ticket must be derived from a password", - sizeof(strresult)); - goto chpwfail; - } - /* construct the ap-rep */ ret = krb5_mk_rep(context, auth_context, &ap_rep); @@ -236,7 +175,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, goto chpwfail; } - /* decrypt the new password */ + /* decrypt the ChangePasswdData */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; @@ -248,20 +187,62 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, goto chpwfail; } - ret = krb5_unparse_name(context, ticket->enc_part2->client, &clientstr); + client = ticket->enc_part2->client; + + /* decode ChangePasswdData for setpw requests */ + if (vno == RFC3244_VERSION) { + krb5_data *clear_data; + + ret = decode_krb5_setpw_req(&clear, &clear_data, &target); + if (ret != 0) { + numresult = KRB5_KPASSWD_MALFORMED; + strlcpy(strresult, "Failed decoding ChangePasswdData", + sizeof(strresult)); + goto chpwfail; + } + + memset(clear.data, 0, clear.length); + free(clear.data); + + clear = *clear_data; + free(clear_data); + + if (target != NULL) { + ret = krb5_unparse_name(context, target, &targetstr); + if (ret != 0) { + numresult = KRB5_KPASSWD_HARDERROR; + strlcpy(strresult, "Failed unparsing target name for log", + sizeof(strresult)); + goto chpwfail; + } + } + } + + ret = krb5_unparse_name(context, client, &clientstr); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed unparsing client name for log", sizeof(strresult)); goto chpwfail; } + + /* for cpw, verify that this is an AS_REQ ticket */ + if (vno == 1 && + (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) { + numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED; + strlcpy(strresult, "Ticket must be derived from a password", + sizeof(strresult)); + goto chpwfail; + } + /* change the password */ ptr = (char *) malloc(clear.length+1); memcpy(ptr, clear.data, clear.length); ptr[clear.length] = '\0'; - ret = schpw_util_wrapper(server_handle, ticket->enc_part2->client, + ret = schpw_util_wrapper(server_handle, client, target, + (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0, ptr, NULL, strresult, sizeof(strresult)); /* zap the password */ @@ -273,27 +254,85 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin, clen = strlen(clientstr); trunc_name(&clen, &cdots); - krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s", - inet_ntoa(((struct sockaddr_in *)&remote_addr)->sin_addr), - (int) clen, clientstr, cdots, - ret ? krb5_get_error_message (context, ret) : "success"); - krb5_free_unparsed_name(context, clientstr); - if (ret) { - if ((ret != KADM5_PASS_Q_TOOSHORT) && - (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && - (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON)) - numresult = KRB5_KPASSWD_HARDERROR; - else - numresult = KRB5_KPASSWD_SOFTERROR; - /* strresult set by kadb5_chpass_principal_util() */ - goto chpwfail; + switch (addr->addrtype) { + case ADDRTYPE_INET: { + struct sockaddr_in *sin = ss2sin(&ss); + + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, addr->contents, addr->length); + sin->sin_port = htons(remote_faddr->port); + salen = sizeof(*sin); + break; + } + case ADDRTYPE_INET6: { + struct sockaddr_in6 *sin6 = ss2sin6(&ss); + + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr, addr->contents, addr->length); + sin6->sin6_port = htons(remote_faddr->port); + salen = sizeof(*sin6); + break; } + default: { + struct sockaddr *sa = ss2sa(&ss); + + sa->sa_family = AF_UNSPEC; + salen = sizeof(*sa); + break; + } + } + + if (getnameinfo(ss2sa(&ss), salen, + addrbuf, sizeof(addrbuf), NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + strlcpy(addrbuf, "<unprintable>", sizeof(addrbuf)); - /* success! */ + if (vno == RFC3244_VERSION) { + size_t tlen; + char *tdots; + const char *targetp; - numresult = KRB5_KPASSWD_SUCCESS; - strlcpy(strresult, "", sizeof(strresult)); + if (target == NULL) { + tlen = clen; + tdots = cdots; + targetp = targetstr; + } else { + tlen = strlen(targetstr); + trunc_name(&tlen, &tdots); + targetp = clientstr; + } + + krb5_klog_syslog(LOG_NOTICE, "setpw request from %s by %.*s%s for %.*s%s: %s", + addrbuf, + (int) clen, clientstr, cdots, + (int) tlen, targetp, tdots, + ret ? krb5_get_error_message (context, ret) : "success"); + } else { + krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s", + addrbuf, + (int) clen, clientstr, cdots, + ret ? krb5_get_error_message (context, ret) : "success"); + } + switch (ret) { + case KADM5_AUTH_CHANGEPW: + numresult = KRB5_KPASSWD_ACCESSDENIED; + break; + case KADM5_PASS_Q_TOOSHORT: + case KADM5_PASS_REUSE: + case KADM5_PASS_Q_CLASS: + case KADM5_PASS_Q_DICT: + case KADM5_PASS_TOOSOON: + numresult = KRB5_KPASSWD_HARDERROR; + break; + case 0: + numresult = KRB5_KPASSWD_SUCCESS; + strlcpy(strresult, "", sizeof(strresult)); + break; + default: + numresult = KRB5_KPASSWD_SOFTERROR; + break; + } chpwfail: @@ -310,8 +349,8 @@ chpwfail: cipher.length = 0; if (ap_rep.length) { - ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, - NULL); + ret = krb5_auth_con_setaddrs(context, auth_context, + local_faddr->address, NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, @@ -422,8 +461,12 @@ bailout: krb5_xfree(clear.data); if (cipher.length) krb5_xfree(cipher.data); - if (allocated_mem) - krb5_xfree(local_kaddr.contents); + if (target) + krb5_free_principal(context, target); + if (targetstr) + krb5_free_unparsed_name(context, targetstr); + if (clientstr) + krb5_free_unparsed_name(context, clientstr); return(ret); } diff --git a/src/kadmin/testing/util/Makefile.in b/src/kadmin/testing/util/Makefile.in index 2f5760d..41d6ead 100644 --- a/src/kadmin/testing/util/Makefile.in +++ b/src/kadmin/testing/util/Makefile.in @@ -56,8 +56,7 @@ $(OUTPRE)tcl_ovsec_kadm.$(OBJEXT): $(BUILDTOP)/include/autoconf.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/k5-platform.h \ - $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/gssrpc/xdr.h $(SRCTOP)/include/kdb.h \ $(SRCTOP)/include/krb5.h tcl_kadm5.h tcl_ovsec_kadm.c $(OUTPRE)tcl_kadm5.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ @@ -68,8 +67,7 @@ $(OUTPRE)tcl_kadm5.$(OBJEXT): $(BUILDTOP)/include/autoconf.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/k5-platform.h \ - $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/gssrpc/xdr.h $(SRCTOP)/include/kdb.h \ $(SRCTOP)/include/krb5.h tcl_kadm5.c tcl_kadm5.h $(OUTPRE)test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ tcl_kadm5.h test.c |