From: Ken Raeburn Date: Wed, 17 Mar 2010 06:00:56 +0000 (+0000) Subject: Merge users/raeburn/branches/network-merge X-Git-Tag: krb5-1.9-beta1~310 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=17d926a4ce8bc2ede57a86f23948a3e9b68266a6;p=krb5.git Merge users/raeburn/branches/network-merge Re-integrates the forked versions of network.c in kdc and kadmin/server. Server-specific initialization and SIGHUP-reset code is moved into other source files; the more generic network-servicing code is merged and moved into apputils library already used by both programs. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23811 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/net-server.h b/src/include/net-server.h new file mode 100644 index 000000000..02f35e160 --- /dev/null +++ b/src/include/net-server.h @@ -0,0 +1,50 @@ +/* */ + +#ifndef NET_SERVER_H +#define NET_SERVER_H + +typedef struct _krb5_fulladdr { + krb5_address * address; + krb5_ui_4 port; +} krb5_fulladdr; + +/* exported from network.c */ +extern volatile int signal_requests_exit, signal_requests_reset; +void init_addr(krb5_fulladdr *, struct sockaddr *); +krb5_error_code add_udp_port(int port); +krb5_error_code add_tcp_port(int port); +krb5_error_code add_rpc_service(int port, u_long prognum, u_long versnum, + void (*dispatch)()); +krb5_error_code setup_network(void *handle, const char *prog); +krb5_error_code listen_and_process(void *handle, const char *prog, + void (*reset)(void)); +void closedown_network(void); + +/* to be supplied by the server application */ + +/* + * Two routines for processing an incoming message and getting a + * result to send back. + * + * The first, dispatch(), is for normal processing of a request. The + * second, make_toolong_error(), is obviously for generating an error + * to send back when the incoming message is bigger than + * listen_and_process can accept. + */ +krb5_error_code dispatch (void *handle, + struct sockaddr *local_addr, + const krb5_fulladdr *remote_addr, + krb5_data *request, + krb5_data **response, + int is_tcp); +krb5_error_code make_toolong_error (void *handle, krb5_data **); + +/* + * Contexts are needed in lots of places. Opaque application-provided + * handles are passed around in lots of place, but contexts are not. + * For now, we'll require that the application provide us an easy way + * to get at a context; eventually it should probably be explicity. + */ +krb5_context get_context(void *handle); + +#endif /* NET_SERVER_H */ diff --git a/src/kadmin/server/Makefile.in b/src/kadmin/server/Makefile.in index ec30c7769..d3111da4a 100644 --- a/src/kadmin/server/Makefile.in +++ b/src/kadmin/server/Makefile.in @@ -11,13 +11,13 @@ 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 ipropd_svc.o network.o -SRCS = kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c schpw.c misc.c ipropd_svc.c network.c +OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o ipropd_svc.o +SRCS = kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c schpw.c misc.c ipropd_svc.c all:: $(PROG) $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(APPUTILS_DEPLIB) - $(CC_LINK) -o $(PROG) $(OBJS) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS) $(APPUTILS_LIB) + $(CC_LINK) -o $(PROG) $(OBJS) $(APPUTILS_LIB) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS) install:: $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(SERVER_BINDIR)/$(PROG) diff --git a/src/kadmin/server/deps b/src/kadmin/server/deps index e30643818..8f73320f4 100644 --- a/src/kadmin/server/deps +++ b/src/kadmin/server/deps @@ -14,7 +14,7 @@ $(OUTPRE)kadm_rpc_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/gssrpc/rpc_msg.h $(top_srcdir)/include/gssrpc/svc.h \ $(top_srcdir)/include/gssrpc/svc_auth.h $(top_srcdir)/include/gssrpc/xdr.h \ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ - kadm_rpc_svc.c misc.h + $(top_srcdir)/include/net-server.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 \ @@ -28,7 +28,8 @@ $(OUTPRE)server_stubs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \ $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \ $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/kdb.h \ - $(top_srcdir)/include/krb5.h misc.h server_stubs.c + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/net-server.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 \ @@ -52,15 +53,17 @@ $(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/kdb_kt.h \ $(top_srcdir)/include/kdb_log.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h $(top_srcdir)/lib/gssapi/generic/gssapiP_generic.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/net-server.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + $(top_srcdir)/lib/gssapi/generic/gssapiP_generic.h \ $(top_srcdir)/lib/gssapi/generic/gssapi_ext.h $(top_srcdir)/lib/gssapi/generic/gssapi_generic.h \ $(top_srcdir)/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 \ - $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.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) $(top_srcdir)/include/adm_proto.h $(top_srcdir)/include/gssrpc/auth.h \ $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \ @@ -74,8 +77,8 @@ $(OUTPRE)schpw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - misc.h schpw.c + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h misc.h schpw.c $(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 \ @@ -94,8 +97,8 @@ $(OUTPRE)misc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - misc.c misc.h + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h misc.c misc.h $(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 \ @@ -112,27 +115,5 @@ $(OUTPRE)ipropd_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/iprop_hdr.h $(top_srcdir)/include/k5-platform.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/kdb_log.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/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)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h \ - $(top_srcdir)/include/cm.h $(top_srcdir)/include/fake-addrinfo.h \ - $(top_srcdir)/include/foreachaddr.h $(top_srcdir)/include/gssrpc/auth.h \ - $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \ - $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \ - $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \ - $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \ - $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/iprop.h \ - $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ - $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ - $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ - $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h misc.h network.c + $(top_srcdir)/include/net-server.h $(top_srcdir)/lib/kadm5/srv/server_acl.h \ + ipropd_svc.c misc.h diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c index 375fbd151..b9212fa0f 100644 --- a/src/kadmin/server/misc.c +++ b/src/kadmin/server/misc.c @@ -9,6 +9,7 @@ #include #include #include "misc.h" +#include "net-server.h" /* * Function: chpass_principal_wrapper_3 @@ -224,3 +225,47 @@ trunc_name(size_t *len, char **dots) *dots = *len > MAXPRINCLEN ? "..." : ""; *len = *len > MAXPRINCLEN ? MAXPRINCLEN : *len; } + +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; +} + +krb5_context get_context(void *handle) +{ + kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; + return server_handle->context; +} diff --git a/src/kadmin/server/misc.h b/src/kadmin/server/misc.h index 10e6054db..35f299401 100644 --- a/src/kadmin/server/misc.h +++ b/src/kadmin/server/misc.h @@ -7,10 +7,7 @@ #ifndef _MISC_H #define _MISC_H 1 -typedef struct _krb5_fulladdr { - krb5_address * address; - krb5_ui_4 port; -} krb5_fulladdr; +#include "net-server.h" /* for krb5_fulladdr */ void log_badauth(OM_uint32 major, OM_uint32 minor, @@ -64,18 +61,13 @@ 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); +#include "net-server.h" void diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c index bcc4f16cd..417363794 100644 --- a/src/kadmin/server/ovsec_kadmd.c +++ b/src/kadmin/server/ovsec_kadmd.c @@ -72,8 +72,6 @@ void request_pure_clear(int); extern int daemon(int, int); #endif -volatile int signal_request_exit = 0; -volatile int signal_request_hup = 0; void setup_signal_handlers(iprop_role iproprole); void request_exit(int); void request_hup(int); @@ -383,7 +381,20 @@ int main(int argc, char *argv[]) exit(1); } - if ((ret = setup_network(global_server_handle, whoami))) { +#define server_handle ((kadm5_server_handle_t)global_server_handle) + if ((ret = add_udp_port(server_handle->params.kpasswd_port)) + || (ret = add_tcp_port(server_handle->params.kpasswd_port)) + || (ret = add_rpc_service(server_handle->params.kadmind_port, + KADM, KADMVERS, kadm_1)) +#ifndef DISABLE_IPROP + || (server_handle->params.iprop_enabled + ? (ret = add_rpc_service(server_handle->params.iprop_port, + KRB5_IPROP_PROG, KRB5_IPROP_VERS, + krb5_iprop_prog_1)) + : 0) +#endif +#undef server_handle + || (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); @@ -632,13 +643,13 @@ kterr: if (nofork) fprintf(stderr, "%s: starting...\n", whoami); - listen_and_process(global_server_handle, whoami); + listen_and_process(global_server_handle, whoami, reset_db); krb5_klog_syslog(LOG_INFO, "finished, exiting"); /* Clean up memory, etc */ svcauth_gssapi_unset_names(); kadm5_destroy(global_server_handle); - closedown_network(global_server_handle, whoami); + closedown_network(); kadm5int_acl_finish(context, 0); if(gss_changepw_name) { (void) gss_release_name(&OMret, &gss_changepw_name); @@ -765,12 +776,12 @@ void request_pure_clear(int signum) * Requires: * Effects: * Modifies: - * sets signal_request_hup to one + * sets signal_requests_reset to one */ void request_hup(int signum) { - signal_request_hup = 1; + signal_requests_reset = 1; return; } @@ -783,7 +794,7 @@ void request_hup(int signum) * Requires: * Effects: * - * Currently, just sets signal_request_reset to 0. The kdb and adb + * Currently, just sets signal_requests_reset to 0. The kdb and adb * libraries used to be sufficiently broken that it was prudent to * close and reopen the databases periodically. They are no longer * that broken, so this function is not necessary. @@ -815,17 +826,17 @@ void reset_db(void) * Arguments: * Requires: * Effects: - * modifies signal_request_exit which ideally makes the server exit + * modifies signal_requests_exit which ideally makes the server exit * at some point. * * Modifies: - * signal_request_exit + * signal_requests_exit */ void request_exit(int signum) { krb5_klog_syslog(LOG_DEBUG, "Got signal to request exit"); - signal_request_exit = 1; + signal_requests_exit = 1; return; } diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c index c1b221732..1124445b4 100644 --- a/src/kadmin/server/schpw.c +++ b/src/kadmin/server/schpw.c @@ -6,6 +6,8 @@ #include #include +#include "kadm5/server_internal.h" /* XXX for kadm5_server_handle_t */ + #include "misc.h" #ifndef GETSOCKNAME_ARG3_TYPE @@ -476,3 +478,60 @@ bailout: return(ret); } + +/* Dispatch routine for set/change password */ +krb5_error_code +dispatch(void *handle, + struct sockaddr *local_saddr, const krb5_fulladdr *remote_faddr, + krb5_data *request, krb5_data **response, int is_tcp) +{ + 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; +} diff --git a/src/kdc/Makefile.in b/src/kdc/Makefile.in index 5c0343d96..49e4a35a4 100644 --- a/src/kdc/Makefile.in +++ b/src/kdc/Makefile.in @@ -26,7 +26,6 @@ SRCS= \ $(srcdir)/kdc_util.c \ $(srcdir)/kdc_preauth.c \ $(srcdir)/main.c \ - $(srcdir)/network.c \ $(srcdir)/policy.c \ $(srcdir)/extern.c \ $(srcdir)/replay.c \ @@ -41,7 +40,6 @@ OBJS= \ kdc_util.o \ kdc_preauth.o \ main.o \ - network.o \ policy.o \ extern.o \ replay.o \ @@ -61,7 +59,7 @@ kdc5_err.h: kdc5_err.et kdc5_err.o: kdc5_err.h krb5kdc: $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(APPUTILS_DEPLIB) - $(CC_LINK) -o krb5kdc $(OBJS) $(KADMSRV_LIBS) $(KRB5_BASE_LIBS) $(APPUTILS_LIB) + $(CC_LINK) -o krb5kdc $(OBJS) $(APPUTILS_LIB) $(KADMSRV_LIBS) $(KRB5_BASE_LIBS) rtest: $(RT_OBJS) $(KDB5_DEPLIBS) $(KADM_COMM_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o rtest $(RT_OBJS) $(KDB5_LIBS) $(KADM_COMM_LIBS) $(KRB5_BASE_LIBS) diff --git a/src/kdc/deps b/src/kdc/deps index bd3b4e021..636090565 100644 --- a/src/kdc/deps +++ b/src/kdc/deps @@ -11,9 +11,9 @@ $(OUTPRE)dispatch.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h dispatch.c extern.h \ - kdc_util.h + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/net-server.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + dispatch.c extern.h kdc_util.h $(OUTPRE)do_as_req.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm.h \ @@ -24,8 +24,9 @@ $(OUTPRE)do_as_req.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - do_as_req.c extern.h kdc_util.h policy.h + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h do_as_req.c extern.h \ + kdc_util.h policy.h $(OUTPRE)do_tgs_req.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h \ @@ -35,9 +36,9 @@ $(OUTPRE)do_tgs_req.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h do_tgs_req.c extern.h \ - kdc_util.h policy.h + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/net-server.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + do_tgs_req.c extern.h kdc_util.h policy.h $(OUTPRE)fast_util.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -47,8 +48,9 @@ $(OUTPRE)fast_util.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h fast_util.c kdc_util.h + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h extern.h fast_util.c \ + kdc_util.h $(OUTPRE)kdc_util.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm.h \ @@ -59,8 +61,9 @@ $(OUTPRE)kdc_util.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h kdc_util.c kdc_util.h + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h extern.h kdc_util.c \ + kdc_util.h $(OUTPRE)kdc_preauth.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../include/krb5/preauth_plugin.h \ @@ -71,8 +74,9 @@ $(OUTPRE)kdc_preauth.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h kdc_preauth.c kdc_util.h + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h extern.h kdc_preauth.c \ + kdc_util.h $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm.h \ @@ -83,22 +87,9 @@ $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/kdb_kt.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h extern.h kdc5_err.h \ - kdc_util.h main.c -$(OUTPRE)network.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ - $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h \ - $(top_srcdir)/include/cm.h $(top_srcdir)/include/fake-addrinfo.h \ - $(top_srcdir)/include/foreachaddr.h $(top_srcdir)/include/k5-buf.h \ - $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ - $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ - $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ - $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ - $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ - $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/net-server.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h kdc5_err.h kdc_util.h network.c + extern.h kdc5_err.h kdc_util.h main.c $(OUTPRE)policy.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -108,8 +99,9 @@ $(OUTPRE)policy.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h kdc_util.h policy.c + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h extern.h kdc_util.h \ + policy.c $(OUTPRE)extern.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ @@ -130,8 +122,9 @@ $(OUTPRE)replay.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - extern.h kdc_util.h replay.c + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h extern.h kdc_util.h \ + replay.c $(OUTPRE)kdc_authdata.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h \ @@ -141,6 +134,6 @@ $(OUTPRE)kdc_authdata.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h extern.h kdc_authdata.c \ - kdc_util.h + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/net-server.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + extern.h kdc_authdata.c kdc_util.h diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c index a8d95229d..207fa390a 100644 --- a/src/kdc/dispatch.c +++ b/src/kdc/dispatch.c @@ -38,8 +38,11 @@ static krb5_int32 last_usec = 0, last_os_random = 0; +static krb5_error_code make_too_big_error (krb5_data **out); + krb5_error_code -dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response) +dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from, + krb5_data *pkt, krb5_data **response, int is_tcp) { krb5_error_code retval; @@ -55,6 +58,9 @@ dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response) const char *name = 0; char buf[46]; + if (is_tcp == 0 && (*response)->length > max_dgram_reply_size) + goto too_big_for_udp; + name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype), from->address->contents, buf, sizeof (buf)); if (name == 0) @@ -109,5 +115,49 @@ dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response) kdc_insert_lookaside(pkt, *response); #endif + if (is_tcp == 0 && (*response)->length > max_dgram_reply_size) { + too_big_for_udp: + krb5_free_data(kdc_context, *response); + retval = make_too_big_error(response); + if (retval) { + krb5_klog_syslog(LOG_ERR, + "error constructing KRB_ERR_RESPONSE_TOO_BIG error: %s", + error_message(retval)); + } + } + return retval; } + +static krb5_error_code +make_too_big_error (krb5_data **out) +{ + krb5_error errpkt; + krb5_error_code retval; + krb5_data *scratch; + + *out = NULL; + memset(&errpkt, 0, sizeof(errpkt)); + + retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); + if (retval) + return retval; + errpkt.error = KRB_ERR_RESPONSE_TOO_BIG; + errpkt.server = tgs_server; + errpkt.client = NULL; + 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(kdc_context, &errpkt, scratch); + if (retval) { + free(scratch); + return retval; + } + + *out = scratch; + return 0; +} diff --git a/src/kdc/extern.c b/src/kdc/extern.c index 763adf57d..effa42579 100644 --- a/src/kdc/extern.c +++ b/src/kdc/extern.c @@ -40,6 +40,3 @@ krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */ krb5_rcache kdc_rcache = (krb5_rcache) NULL; krb5_keyblock psr_key; krb5_int32 max_dgram_reply_size = MAX_DGRAM_SIZE; - -volatile int signal_requests_exit = 0; /* gets set when signal hits */ -volatile int signal_requests_hup = 0; /* ditto */ diff --git a/src/kdc/extern.h b/src/kdc/extern.h index 2f5dc0b9c..41ed439b8 100644 --- a/src/kdc/extern.h +++ b/src/kdc/extern.h @@ -106,7 +106,4 @@ extern const int kdc_modifies_kdb; extern krb5_int32 max_dgram_reply_size; /* maximum datagram size */ extern const int vague_errors; - -extern volatile int signal_requests_exit; -extern volatile int signal_requests_hup; #endif /* __KRB5_KDC_EXTERN__ */ diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index d63bba253..6fa2d73a2 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -63,6 +63,7 @@ #include #include "adm.h" #include "adm_proto.h" +#include "net-server.h" #include #ifdef USE_RCACHE @@ -2771,3 +2772,50 @@ krb5int_get_domain_realm_mapping(krb5_context context, *realmsp = retrealms; return 0; } + +krb5_error_code +make_toolong_error (void *handle, krb5_data **out) +{ + krb5_error errpkt; + krb5_error_code retval; + krb5_data *scratch; + + retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); + if (retval) + return retval; + errpkt.error = KRB_ERR_FIELD_TOOLONG; + errpkt.server = tgs_server; + 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(kdc_context, &errpkt, scratch); + if (retval) { + free(scratch); + return retval; + } + + *out = scratch; + return 0; +} + +krb5_context get_context(void *handle) +{ + return kdc_context; +} + +void reset_for_hangup() +{ + int k; + + for (k = 0; k < kdc_numrealms; k++) + krb5_db_invoke(kdc_realmlist[k]->realm_context, + KRB5_KDB_METHOD_REFRESH_POLICY, + NULL, NULL); +} diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 03ecaf7c1..d6a2d720c 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -32,11 +32,7 @@ #define __KRB5_KDC_UTIL__ #include "kdb.h" - -typedef struct _krb5_fulladdr { - krb5_address * address; - krb5_ui_4 port; -} krb5_fulladdr; +#include "net-server.h" krb5_error_code check_hot_list (krb5_ticket *); krb5_boolean realm_compare (krb5_const_principal, krb5_const_principal); @@ -137,9 +133,12 @@ process_tgs_req (krb5_data *, krb5_data ** ); /* dispatch.c */ krb5_error_code -dispatch (krb5_data *, +dispatch (void *, + struct sockaddr *, const krb5_fulladdr *, - krb5_data **); + krb5_data *, + krb5_data **, + int); /* main.c */ krb5_error_code kdc_initialize_rcache (krb5_context, char *); @@ -153,11 +152,6 @@ kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...) #endif ; -/* network.c */ -krb5_error_code listen_and_process (void); -krb5_error_code setup_network (void); -krb5_error_code closedown_network (void); - /* policy.c */ int against_local_policy_as (krb5_kdc_req *, krb5_db_entry, @@ -240,6 +234,8 @@ void kdc_insert_lookaside (krb5_data *, krb5_data *); void kdc_free_lookaside(krb5_context); /* kdc_util.c */ +void reset_for_hangup(void); + krb5_error_code get_principal_locked (krb5_context kcontext, krb5_const_principal search_for, diff --git a/src/kdc/main.c b/src/kdc/main.c index 9d8022a78..eaa70626f 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "k5-int.h" #include "com_err.h" @@ -69,6 +70,7 @@ #include "extern.h" #include "kdc5_err.h" #include "kdb_kt.h" +#include "net-server.h" #ifdef HAVE_NETINET_IN_H #include #endif @@ -519,7 +521,7 @@ request_exit(int signo) static krb5_sigtype request_hup(int signo) { - signal_requests_hup = 1; + signal_requests_reset = 1; #ifdef POSIX_SIGTYPE return; @@ -865,6 +867,7 @@ int main(int argc, char **argv) krb5_error_code retval; krb5_context kcontext; int errout = 0; + int i; if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; @@ -915,7 +918,40 @@ int main(int argc, char **argv) return 1; } - if ((retval = setup_network())) { + /* Handle each realm's ports */ + for (i=0; irealm_ports; + int port; + while (cp && *cp) { + if (*cp == ',' || isspace((int) *cp)) { + cp++; + continue; + } + port = strtol(cp, &cp, 10); + if (cp == 0) + break; + retval = add_udp_port(port); + if (retval) + goto net_init_error; + } + + cp = kdc_realmlist[i]->realm_tcp_ports; + while (cp && *cp) { + if (*cp == ',' || isspace((int) *cp)) { + cp++; + continue; + } + port = strtol(cp, &cp, 10); + if (cp == 0) + break; + retval = add_tcp_port(port); + if (retval) + goto net_init_error; + } + } + + if ((retval = setup_network(NULL, kdc_progname))) { + net_init_error: kdc_err(kcontext, retval, "while initializing network"); finish_realms(); return 1; @@ -936,14 +972,11 @@ int main(int argc, char **argv) krb5_klog_syslog(LOG_INFO, "commencing operation"); if (nofork) fprintf(stderr, "%s: starting...\n", kdc_progname); - if ((retval = listen_and_process())) { + if ((retval = listen_and_process(0, kdc_progname, reset_for_hangup))) { kdc_err(kcontext, retval, "while processing network requests"); errout++; } - if ((retval = closedown_network())) { - kdc_err(kcontext, retval, "while shutting down network"); - errout++; - } + closedown_network(); krb5_klog_syslog(LOG_INFO, "shutting down"); unload_preauth_plugins(kcontext); unload_authdata_plugins(kcontext); diff --git a/src/kdc/network.c b/src/kdc/network.c deleted file mode 100644 index dfb478c9c..000000000 --- a/src/kdc/network.c +++ /dev/null @@ -1,1764 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - * kdc/network.c - * - * Copyright 1990,2000,2007,2008,2009 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 KDC. - */ - -#include "k5-int.h" -#include "kdc_util.h" -#include "extern.h" -#include "kdc5_err.h" -#include "adm_proto.h" -#include -#include - -#include -#include -#include "port-sockets.h" -#include "socket-utils.h" - -#ifdef HAVE_NETINET_IN_H -#include -#include -#include -#ifdef HAVE_SYS_SOCKIO_H -/* for SIOCGIFCONF, etc. */ -#include -#endif -#include -#if HAVE_SYS_SELECT_H -#include -#endif -#include - -#ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */ -#include -#endif - -#ifdef HAVE_SYS_FILIO_H -#include /* FIONBIO */ -#endif - -#include "fake-addrinfo.h" - -/* 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, "", 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; -} - -/* KDC data. */ - -enum conn_type { - CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, CONN_TCP, - CONN_ROUTING -}; - -/* Per-connection info. */ -struct connection { - int fd; - enum conn_type type; - void (*service)(struct connection *, 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; - } 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 connections; */ -static SET(struct connection *) connections; -#define n_sockets connections.n -#define conns connections.data - -/* Set udp_port_data, tcp_port_data; */ -/* - * N.B.: The Emacs cc-mode indentation code seems to get confused if - * the macro argument here is one word only. So use "unsigned short" - * instead of the "u_short" we were using before. - */ -static SET(unsigned short) udp_port_data, tcp_port_data; - -#include "cm.h" - -static struct select_state sstate; - -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; -} - - -#define USE_AF AF_INET -#define USE_TYPE SOCK_DGRAM -#define USE_PROTO 0 -#define SOCKET_ERRNO errno -#include "foreachaddr.h" - -struct socksetup { - 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 conn_type conntype, - void (*service)(struct connection *, int)) -{ - struct connection *newconn; - void *tmp; - -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { - data->retval = EMFILE; /* XXX */ - kdc_err(NULL, 0, "file descriptor number %d too high", sock); - return 0; - } -#endif - newconn = malloc(sizeof(*newconn)); - if (newconn == 0) { - data->retval = ENOMEM; - kdc_err(NULL, ENOMEM, "cannot allocate storage for connection info"); - return 0; - } - if (!ADD(connections, newconn, tmp)) { - data->retval = ENOMEM; - kdc_err(NULL, 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(struct connection *, int); -static void accept_tcp_connection(struct connection *, int); -static void process_tcp_connection(struct connection *, 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 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) { - kdc_err(NULL, errno, "Cannot create TCP server socket on %s", - paddr(addr)); - return -1; - } - set_cloexec_fd(sock); -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { - close(sock); - kdc_err(NULL, 0, "TCP socket fd number %d (for %s) too high", - sock, paddr(addr)); - return -1; - } -#endif - if (setreuseaddr(sock, 1) < 0) - kdc_err(NULL, 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)) - kdc_err(NULL, errno, "setsockopt(%d,IPV6_V6ONLY,1) failed", sock); - else - kdc_err(NULL, 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) { - kdc_err(NULL, errno, "Cannot bind TCP server socket on %s", - paddr(addr)); - close(sock); - return -1; - } - if (listen(sock, 5) < 0) { - kdc_err(NULL, errno, "Cannot listen on TCP server socket on %s", - paddr(addr)); - close(sock); - return -1; - } - if (setnbio(sock)) { - kdc_err(NULL, errno, - "cannot set listening tcp socket on %s non-blocking", - paddr(addr)); - close(sock); - return -1; - } - if (setnolinger(sock)) { - kdc_err(NULL, errno, "disabling SO_LINGER on TCP 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; -} - -#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; - kdc_err(NULL, 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)) - kdc_err(NULL, errno, "setsockopt(%d,IPV6_V6ONLY,1) failed", - sock); - else - kdc_err(NULL, 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; - kdc_err(NULL, 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) { - kdc_err(NULL, 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, "", 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 - -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(struct connection *conn, int selflags) -{ - int n_read; - struct rt_msghdr rtm; - - 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; - } - } -#if 0 - 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); -#endif - 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: - /* - * Some flags indicate routing table updates that don't - * indicate local address changes. They may come from - * redirects, or ARP, etc. - * - * This set of symbols is just an initial guess based on - * some messages observed in real life; working out which - * other flags also indicate messages we should ignore, - * and which flags are portable to all system and thus - * don't need to be conditionalized, is left as a future - * exercise. - */ -#ifdef RTF_DYNAMIC - if (rtm.rtm_flags & RTF_DYNAMIC) - break; -#endif -#ifdef RTF_CLONED - if (rtm.rtm_flags & RTF_CLONED) - break; -#endif -#ifdef RTF_LLINFO - if (rtm.rtm_flags & RTF_LLINFO) - break; -#endif -#if 0 - krb5_klog_syslog(LOG_DEBUG, - "network reconfiguration message (%s) received", - rtm_type_name(rtm.rtm_type)); -#endif - 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. */ -#if 0 - krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting"); -#endif - break; - default: - krb5_klog_syslog(LOG_INFO, - "unhandled routing message type %d, will reconfigure just for the fun of it", - rtm.rtm_type); - 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() -{ - struct socksetup setup_data; - krb5_error_code retval; - char *cp; - int i, port; - - 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; - - /* Handle each realm's ports */ - for (i=0; irealm_ports; - while (cp && *cp) { - if (*cp == ',' || isspace((int) *cp)) { - cp++; - continue; - } - port = strtol(cp, &cp, 10); - if (cp == 0) - break; - retval = add_udp_port(port); - if (retval) - return retval; - } - - cp = kdc_realmlist[i]->realm_tcp_ports; - while (cp && *cp) { - if (*cp == ',' || isspace((int) *cp)) { - cp++; - continue; - } - port = strtol(cp, &cp, 10); - if (cp == 0) - break; - retval = add_tcp_port(port); - if (retval) - return retval; - } - } - - 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); - krb5_klog_syslog (LOG_INFO, "set up %d sockets", n_sockets); - if (n_sockets == 0) { - kdc_err(NULL, 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; - } -} - -/* - * This holds whatever additional information might be needed to - * properly send back to the client from the correct local address. - * - * In this case, we only need one datum so far: On Mac OS X, the - * kernel doesn't seem to like sending from link-local addresses - * unless we specify the correct interface. - */ - -union aux_addressing_info { - int ipv6_ifindex; -}; - -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, - union aux_addressing_info *auxaddr) -{ -#if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE) - if (to && tolen) { - /* Clobber with something recognizeable in case we try to use - the address. */ - memset(to, 0x40, *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); - - /* Clobber with something recognizeable in case we can't extract - the address but try to use it anyways. */ - memset(to, 0x40, *tolen); - - 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); - auxaddr->ipv6_ifindex = pktinfo->ipi6_ifindex; - 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, - union aux_addressing_info *auxaddr) -{ -#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; - /* - * Because of the possibility of asymmetric routing, we - * normally don't want to specify an interface. However, - * Mac OS X doesn't like sending from a link-local address - * (which can come up in testing at least, if you wind up - * with a "foo.local" name) unless we do specify the - * interface. - */ - if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr)) - p->ipi6_ifindex = auxaddr->ipv6_ifindex; - /* otherwise, already zero */ - } - msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - break; -#endif - default: - goto use_sendto; - } - return sendmsg(s, &msg, flags); -#endif -} - -static krb5_error_code -make_too_big_error (krb5_data **out) -{ - krb5_error errpkt; - krb5_error_code retval; - krb5_data *scratch; - - *out = NULL; - memset(&errpkt, 0, sizeof(errpkt)); - - retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); - if (retval) - return retval; - errpkt.error = KRB_ERR_RESPONSE_TOO_BIG; - errpkt.server = tgs_server; - errpkt.client = NULL; - 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(kdc_context, &errpkt, scratch); - if (retval) { - free(scratch); - return retval; - } - - *out = scratch; - return 0; -} - -static void process_packet(struct connection *conn, 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; - union aux_addressing_info auxaddr; - - response = NULL; - saddr_len = sizeof(saddr); - daddr_len = sizeof(daddr); - memset(&auxaddr, 0, sizeof(auxaddr)); - cc = recv_from_to(port_fd, pktbuf, sizeof(pktbuf), 0, - (struct sockaddr *)&saddr, &saddr_len, - (struct sockaddr *)&daddr, &daddr_len, - &auxaddr); - 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 - ) - kdc_err(NULL, 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)); - kdc_err(NULL, 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(&request, &faddr, &response))) { - kdc_err(NULL, retval, "while dispatching (udp)"); - return; - } - if (response == NULL) - return; - if (response->length > max_dgram_reply_size) { - krb5_free_data(kdc_context, response); - retval = make_too_big_error(&response); - if (retval) { - krb5_klog_syslog(LOG_ERR, - "error constructing KRB_ERR_RESPONSE_TOO_BIG error: %s", - error_message(retval)); - return; - } - } - cc = send_to_from(port_fd, response->data, (socklen_t) response->length, 0, - (struct sockaddr *)&saddr, saddr_len, - (struct sockaddr *)&daddr, daddr_len, - &auxaddr); - if (cc == -1) { - /* - * Note that the local address (daddr*) has no port number - * info associated with it. - */ - char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV]; - char daddrbuf[NI_MAXHOST]; - int e = errno; - krb5_free_data(kdc_context, response); - if (getnameinfo((struct sockaddr *)&daddr, daddr_len, - daddrbuf, sizeof(daddrbuf), 0, 0, - NI_NUMERICHOST) != 0) { - strlcpy(daddrbuf, "?", sizeof(daddrbuf)); - } - if (getnameinfo((struct sockaddr *)&saddr, saddr_len, - saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf), - NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - strlcpy(saddrbuf, "?", sizeof(saddrbuf)); - strlcpy(sportbuf, "?", sizeof(sportbuf)); - } - kdc_err(NULL, e, "while sending reply to %s/%s from %s", - saddrbuf, sportbuf, daddrbuf); - return; - } - if (cc != response->length) { - kdc_err(NULL, 0, "short reply write %d vs %d\n", - response->length, cc); - } - krb5_free_data(kdc_context, response); - return; -} - -static int tcp_data_counter; -static int max_tcp_data_connections = 30; - -static void kill_tcp_connection(struct connection *); - -static void accept_tcp_connection(struct connection *conn, 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.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_data_counter > max_tcp_data_connections) { - struct connection *oldest_tcp = NULL; - struct connection *c; - int i; - - krb5_klog_syslog(LOG_INFO, "too many connections"); - - FOREACH_ELT (connections, i, c) { - if (c->type != CONN_TCP) - 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 tcp fd %d from %s", - oldest_tcp->fd, oldest_tcp->u.tcp.addrbuf); - kill_tcp_connection(oldest_tcp); - } - } - if (newconn->u.tcp.buffer == 0) { - kdc_err(NULL, errno, "allocating buffer for new TCP session from %s", - newconn->u.tcp.addrbuf); - delete_fd(newconn); - close(s); - tcp_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_connection(struct connection *conn) -{ - if (conn->u.tcp.response) - krb5_free_data(kdc_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--; - close(conn->fd); - conn->fd = -1; - delete_fd(conn); - tcp_data_counter--; -} - -static krb5_error_code -make_toolong_error (krb5_data **out) -{ - krb5_error errpkt; - krb5_error_code retval; - krb5_data *scratch; - - retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); - if (retval) - return retval; - errpkt.error = KRB_ERR_FIELD_TOOLONG; - errpkt.server = tgs_server; - 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(kdc_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(struct connection *conn, int selflags) -{ - 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 */ - 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. */ - 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 (&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; - - 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; - err = dispatch(&request, &conn->u.tcp.faddr, - &conn->u.tcp.response); - if (err) { - kdc_err(NULL, 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_connection(conn); -} - -static void service_conn(struct connection *conn, int selflags) -{ - conn->service(conn, selflags); -} - -/* from sendto_kdc.c */ -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() -{ - 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; - - if (conns == (struct connection **) NULL) - return KDC5_NONET; - - while (!signal_requests_exit) { - if (signal_requests_hup) { - int k; - - krb5_klog_reopen(kdc_context); - for (k = 0; k < kdc_numrealms; k++) - krb5_db_invoke(kdc_realmlist[k]->realm_context, - KRB5_KDB_METHOD_REFRESH_POLICY, - NULL, NULL); - signal_requests_hup = 0; - } - - if (network_reconfiguration_needed) { - /* No point in re-logging what we've just logged. */ - if (netchanged == 0) - 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) { - kdc_err(NULL, 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) - kdc_err(NULL, err, "while selecting for network input(1)"); - continue; - } - if (sret == 0 && netchanged) { - network_reconfiguration_needed = 0; - closedown_network(); - err = setup_network(); - if (err) { - kdc_err(NULL, err, "while reinitializing network"); - return err; - } - netchanged = 0; - } - if (sret == -1) { - if (errno != EINTR) - kdc_err(NULL, errno, "while selecting for network input(2)"); - continue; - } - nfound = sret; - for (i=0; i 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(conns[i], sflags); - } - } - krb5_klog_syslog(LOG_INFO, "shutdown signal received"); - return 0; -} - -krb5_error_code -closedown_network() -{ - 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); - } - 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); - - return 0; -} - -#endif /* INET */ diff --git a/src/lib/apputils/Makefile.in b/src/lib/apputils/Makefile.in index 37a77bcb8..58273248b 100644 --- a/src/lib/apputils/Makefile.in +++ b/src/lib/apputils/Makefile.in @@ -13,9 +13,7 @@ DEFS= ##DOS##XTRA= ##DOS##OBJFILE=$(OUTPRE)apputils.lst -# LIBOBJS may or may not contain daemon.o; dummy.o is just here to -# avoid having an empty library. -STLIBOBJS=dummy.o @LIBOBJS@ +STLIBOBJS=net-server.o @LIBOBJS@ STOBJLISTS=OBJS.ST LIBBASE=apputils @@ -28,7 +26,7 @@ LINTFILES= daemon.c LIBOBJS=$(OUTPRE)daemon.$(OBJEXT) SRCS= $(srcdir)/daemon.c \ - $(srcdir)/dummy.c + $(srcdir)/net-server.c @libpriv_frag@ @lib_frag@ diff --git a/src/lib/apputils/deps b/src/lib/apputils/deps index c7385886a..6e2aab590 100644 --- a/src/lib/apputils/deps +++ b/src/lib/apputils/deps @@ -11,4 +11,22 @@ daemon.so daemon.po $(OUTPRE)daemon.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \ $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h daemon.c -dummy.so dummy.po $(OUTPRE)dummy.$(OBJEXT): dummy.c +net-server.so net-server.po $(OUTPRE)net-server.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h $(top_srcdir)/include/cm.h \ + $(top_srcdir)/include/fake-addrinfo.h $(top_srcdir)/include/foreachaddr.h \ + $(top_srcdir)/include/gssrpc/auth.h $(top_srcdir)/include/gssrpc/auth_gss.h \ + $(top_srcdir)/include/gssrpc/auth_unix.h $(top_srcdir)/include/gssrpc/clnt.h \ + $(top_srcdir)/include/gssrpc/rename.h $(top_srcdir)/include/gssrpc/rpc.h \ + $(top_srcdir)/include/gssrpc/rpc_msg.h $(top_srcdir)/include/gssrpc/svc.h \ + $(top_srcdir)/include/gssrpc/svc_auth.h $(top_srcdir)/include/gssrpc/xdr.h \ + $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ + $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h net-server.c diff --git a/src/lib/apputils/dummy.c b/src/lib/apputils/dummy.c deleted file mode 100644 index d5b6cc08d..000000000 --- a/src/lib/apputils/dummy.c +++ /dev/null @@ -1 +0,0 @@ -int lib_server_dummy = 0; diff --git a/src/kadmin/server/network.c b/src/lib/apputils/net-server.c similarity index 90% rename from src/kadmin/server/network.c rename to src/lib/apputils/net-server.c index c8ce4f1eb..18582e272 100644 --- a/src/kadmin/server/network.c +++ b/src/lib/apputils/net-server.c @@ -1,8 +1,8 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* - * kadmin/server/network.c + * lib/apputils/net-server.c * - * Copyright 1990,2000,2007,2008,2009 by the Massachusetts Institute of Technology. + * Copyright 1990,2000,2007,2008,2009,2010 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. @@ -24,25 +24,20 @@ * or implied warranty. * * - * Network code for Kerberos v5 kadmin server (based on KDC code). + * Network code for Kerberos v5 servers (kdc, kadmind). */ #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 #include #include -#include #include "port-sockets.h" #include "socket-utils.h" +#include + #ifdef HAVE_NETINET_IN_H #include #include @@ -66,10 +61,15 @@ #endif #include "fake-addrinfo.h" +#include "net-server.h" /* XXX */ #define KDC5_NONET (-1779992062L) +volatile int signal_requests_exit = 0, signal_requests_reset = 0; + +static void closedown_network_sockets(void); + /* Misc utility routines. */ static void set_sa_port(struct sockaddr *addr, int port) @@ -179,7 +179,7 @@ static const char *paddr (struct sockaddr *sa) return buf; } -/* kadmin data. */ +/* KDC data. */ enum conn_type { CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, CONN_TCP, @@ -281,7 +281,7 @@ static SET(struct rpc_svc_data) rpc_svc_data; static struct select_state sstate; static fd_set rpc_listenfds; -static krb5_error_code add_udp_port(int port) +krb5_error_code add_udp_port(int port) { int i; void *tmp; @@ -299,7 +299,7 @@ static krb5_error_code add_udp_port(int port) return 0; } -static krb5_error_code add_tcp_port(int port) +krb5_error_code add_tcp_port(int port) { int i; void *tmp; @@ -317,8 +317,8 @@ static krb5_error_code add_tcp_port(int port) return 0; } -static krb5_error_code add_rpc_service(int port, u_long prognum, u_long versnum, - void (*dispatch)()) +krb5_error_code add_rpc_service(int port, u_long prognum, u_long versnum, + void (*dispatch)()) { int i; void *tmp; @@ -370,7 +370,7 @@ add_fd (struct socksetup *data, int sock, enum conn_type conntype, return 0; } #endif - newconn = (struct connection *)malloc(sizeof(*newconn)); + newconn = malloc(sizeof(*newconn)); if (newconn == NULL) { data->retval = ENOMEM; com_err(data->prog, ENOMEM, @@ -964,7 +964,6 @@ static void process_routing_update(void *handle, struct connection *conn, 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 @@ -983,10 +982,12 @@ static void process_routing_update(void *handle, struct connection *conn, return; } } +#if 0 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); +#endif if (rtm.rtm_msglen > sizeof(rtm)) { /* It appears we get a partial message and the rest is thrown away? */ @@ -1003,7 +1004,35 @@ static void process_routing_update(void *handle, struct connection *conn, case RTM_IFINFO: case RTM_OLDADD: case RTM_OLDDEL: - krb5_klog_syslog(LOG_INFO, "reconfiguration needed"); + /* + * Some flags indicate routing table updates that don't + * indicate local address changes. They may come from + * redirects, or ARP, etc. + * + * This set of symbols is just an initial guess based on + * some messages observed in real life; working out which + * other flags also indicate messages we should ignore, + * and which flags are portable to all system and thus + * don't need to be conditionalized, is left as a future + * exercise. + */ +#ifdef RTF_DYNAMIC + if (rtm.rtm_flags & RTF_DYNAMIC) + break; +#endif +#ifdef RTF_CLONED + if (rtm.rtm_flags & RTF_CLONED) + break; +#endif +#ifdef RTF_LLINFO + if (rtm.rtm_flags & RTF_LLINFO) + break; +#endif +#if 0 + krb5_klog_syslog(LOG_DEBUG, + "network reconfiguration message (%s) received", + rtm_type_name(rtm.rtm_type)); +#endif network_reconfiguration_needed = 1; break; case RTM_RESOLVE: @@ -1016,10 +1045,14 @@ static void process_routing_update(void *handle, struct connection *conn, case RTM_LOSING: case RTM_GET: /* Not interesting. */ +#if 0 krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting"); +#endif break; default: - krb5_klog_syslog(LOG_INFO, "unhandled routing message type, will reconfigure just for the fun of it"); + krb5_klog_syslog(LOG_INFO, + "unhandled routing message type %d, will reconfigure just for the fun of it", + rtm.rtm_type); network_reconfiguration_needed = 1; break; } @@ -1051,8 +1084,6 @@ 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); @@ -1062,30 +1093,6 @@ setup_network(void *handle, const char *prog) /* 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..."); @@ -1114,7 +1121,7 @@ setup_network(void *handle, const char *prog) return 0; } -static void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa) +void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: @@ -1332,63 +1339,6 @@ send_to_from(int s, void *buf, size_t len, int 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) @@ -1404,7 +1354,6 @@ static void process_packet(void *handle, char pktbuf[MAX_DGRAM_SIZE]; int port_fd = conn->fd; union aux_addressing_info auxaddr; - kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; response = NULL; saddr_len = sizeof(saddr); @@ -1453,7 +1402,7 @@ static void process_packet(void *handle, faddr.address = &addr; init_addr(&faddr, ss2sa(&saddr)); /* this address is in net order */ - if ((retval = dispatch(handle, ss2sa(&daddr), &faddr, &request, &response))) { + if ((retval = dispatch(handle, ss2sa(&daddr), &faddr, &request, &response, 0))) { com_err(prog, retval, "while dispatching (udp)"); return; } @@ -1471,7 +1420,7 @@ static void process_packet(void *handle, char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV]; char daddrbuf[NI_MAXHOST]; int e = errno; - krb5_free_data(server_handle->context, response); + krb5_free_data(get_context(handle), response); if (getnameinfo((struct sockaddr *)&daddr, daddr_len, daddrbuf, sizeof(daddrbuf), 0, 0, NI_NUMERICHOST) != 0) { @@ -1491,7 +1440,7 @@ static void process_packet(void *handle, com_err(prog, 0, "short reply write %d vs %d\n", response->length, cc); } - krb5_free_data(server_handle->context, response); + krb5_free_data(get_context(handle), response); return; } @@ -1613,13 +1562,11 @@ static void accept_tcp_connection(void *handle, 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); + krb5_free_data(get_context(handle), conn->u.tcp.response); if (conn->u.tcp.buffer) free(conn->u.tcp.buffer); FD_CLR(conn->fd, &sstate.rfds); @@ -1657,44 +1604,6 @@ kill_tcp_or_rpc_connection(void *handle, struct connection *conn, int isForcedCl 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) { @@ -1819,7 +1728,7 @@ process_tcp_connection(void *handle, } err = dispatch(handle, local_saddrp, &conn->u.tcp.faddr, - &request, &conn->u.tcp.response); + &request, &conn->u.tcp.response, 1); if (err) { com_err(prog, err, "while dispatching (tcp)"); goto kill_tcp_connection; @@ -1858,7 +1767,8 @@ static int getcurtime(struct timeval *tvp) } krb5_error_code -listen_and_process(void *handle, const char *prog) +listen_and_process(void *handle, const char *prog, + void (*reset)(void)) { int nfound; /* This struct contains 3 fd_set objects; on some platforms, they @@ -1867,29 +1777,21 @@ listen_and_process(void *handle, const char *prog) 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; + while (!signal_requests_exit) { + if (signal_requests_reset) { + krb5_klog_reopen(get_context(handle)); + reset(); + signal_requests_reset = 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"); + /* No point in re-logging what we've just logged. */ + if (netchanged == 0) + 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. */ @@ -1911,7 +1813,7 @@ listen_and_process(void *handle, const char *prog) } if (sret == 0 && netchanged) { network_reconfiguration_needed = 0; - closedown_network(handle, prog); + closedown_network_sockets(); err = setup_network(handle, prog); if (err) { com_err(prog, err, "while reinitializing network"); @@ -1941,14 +1843,14 @@ listen_and_process(void *handle, const char *prog) return 0; } -krb5_error_code -closedown_network(void *handle, const char *prog) +static void +closedown_network_sockets() { int i; struct connection *conn; if (conns == (struct connection **) NULL) - return KDC5_NONET; + return; FOREACH_ELT (connections, i, conn) { if (conn->fd >= 0) { @@ -1974,12 +1876,16 @@ closedown_network(void *handle, const char *prog) progress. */ free(conn); } +} + +void +closedown_network() +{ + closedown_network_sockets(); 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,