From a575589ef525fb139cafa0de1a05382845f0afbd Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 9 Jul 2024 11:32:34 +0200 Subject: [PATCH] Add underpinnings of UNIX domain socket support Add sa2sun() and ss2sun() helpers to socket-utils.h. Add UNIX domain socket support to sa_socklen() and print_addr(). Expand buffers for printing addresses to 128 bytes to accomodate the maximum UNIX domain socket path length. Add loop_add_unix_socket() to net-server.c, primarily using the existing TCP support (renamed to "stream"). As there is no standard Kerberos address type for UNIX domain sockets, add basic directional address support. Add a definition for ADDRTYPE_DIRECTIONAL in krb5.h. Add private constant krb5_address objects to libkrb5 for initiator and acceptor directional addresses. Use directional addresses for the KRB-SAFE/KRB-PRIV source address in the kprop and password change protocols when the transport is not IPv4 or IPv6. krb5_address objects are used for auditing purposes in the KDC audit and KDB pluggable interfaces. Add a local-use address type ADDRTYPE_UNIXSOCK for use in these cases. Add a flag to k5_sockaddr_to_address() to indicate whether this address type can be used. Add UNIX domains socket conversion support to the test audit plugin module. [ghudson@mit.edu: combined several commits; used directional addresses for KRB-SAFE/KRB-PRIV; reduced duplication in net-server.c support; wrote commit message. Also based on work by Alexander Bokovoy.] ticket: 9155 --- doc/appdev/refs/macros/index.rst | 2 + src/include/k5-int.h | 12 ++- src/include/krb5/krb5.hin | 9 ++ src/include/net-server.h | 1 + src/include/port-sockets.h | 1 + src/include/socket-utils.h | 14 +++ src/kadmin/server/schpw.c | 6 +- src/kdc/dispatch.c | 2 +- src/kdc/kdc_audit.c | 2 +- src/kdc/kdc_log.c | 8 +- src/kdc/kdc_util.c | 2 +- src/kprop/kprop.c | 4 +- src/kprop/kpropd.c | 4 +- src/lib/apputils/net-server.c | 169 +++++++++++++++++++++++-------- src/lib/krb5/libkrb5.exports | 2 + src/lib/krb5/os/addr.c | 21 +++- src/lib/krb5/os/changepw.c | 6 ++ src/plugins/audit/j_dict.h | 1 + src/plugins/audit/kdc_j_encode.c | 11 ++ 19 files changed, 216 insertions(+), 61 deletions(-) diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst index 645b59f02a..c1bda5c6c4 100644 --- a/doc/appdev/refs/macros/index.rst +++ b/doc/appdev/refs/macros/index.rst @@ -9,6 +9,7 @@ Public ADDRTYPE_ADDRPORT.rst ADDRTYPE_CHAOS.rst + ADDRTYPE_DIRECTIONAL.rst ADDRTYPE_DDP.rst ADDRTYPE_INET.rst ADDRTYPE_INET6.rst @@ -17,6 +18,7 @@ Public ADDRTYPE_IS_LOCAL.rst ADDRTYPE_NETBIOS.rst ADDRTYPE_XNS.rst + ADDRTYPE_UNIXSOCK.rst AD_TYPE_EXTERNAL.rst AD_TYPE_FIELD_TYPE_MASK.rst AD_TYPE_REGISTERED.rst diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 12eb114a4a..ec9e320e16 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -2409,13 +2409,19 @@ krb5_error_code k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); +/* Address objects for initiator and acceptor directional addresses. */ +extern const krb5_address k5_addr_directional_init; +extern const krb5_address k5_addr_directional_accept; + /* * Translate sa to a krb5_address, putting the result in *out with contents - * aliased from *sa. Return KRB5_PROG_ATYPE_NOSUPP if sa is not an IPv4 or - * IPv6 address. + * aliased from *sa. If local_use is true, translate UNIX domain socket names + * to ADDRTYPE_UNIXSOCK; otherwise do not handle them. Return + * KRB5_PROG_ATYPE_NOSUPP if sa cannot be converted. */ krb5_error_code -k5_sockaddr_to_address(const struct sockaddr *sa, krb5_address *out); +k5_sockaddr_to_address(const struct sockaddr *sa, krb5_boolean local_use, + krb5_address *out); /* Place a printable representation of sa (without port) into buf. */ void diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index c6998adc55..b5d295f331 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -322,6 +322,7 @@ typedef struct _krb5_address { /* per Kerberos v5 protocol spec */ #define ADDRTYPE_INET 0x0002 +#define ADDRTYPE_DIRECTIONAL 0x0003 #define ADDRTYPE_CHAOS 0x0005 #define ADDRTYPE_XNS 0x0006 #define ADDRTYPE_ISO 0x0007 @@ -332,6 +333,14 @@ typedef struct _krb5_address { #define ADDRTYPE_ADDRPORT 0x0100 #define ADDRTYPE_IPPORT 0x0101 +/* + * Negative values for the host address type are reserved for local use. Do + * not use these types in Kerberos protocol elements. + */ + +/* The contents field contains a UNIX domain socket path. */ +#define ADDRTYPE_UNIXSOCK (0x8000 | 0x0001) + /* macros to determine if a type is a local type */ #define ADDRTYPE_IS_LOCAL(addrtype) (addrtype & 0x8000) diff --git a/src/include/net-server.h b/src/include/net-server.h index 14fc23a43a..8ac3ff26f8 100644 --- a/src/include/net-server.h +++ b/src/include/net-server.h @@ -59,6 +59,7 @@ krb5_error_code loop_add_rpc_service(int default_port, const char *addresses, u_long prognum, u_long versnum, void (*dispatchfn)(struct svc_req *, SVCXPRT *)); +krb5_error_code loop_add_unix_socket(const char *socket_paths); krb5_error_code loop_setup_network(verto_ctx *ctx, void *handle, const char *progname, diff --git a/src/include/port-sockets.h b/src/include/port-sockets.h index 228e4cf053..459cd86674 100644 --- a/src/include/port-sockets.h +++ b/src/include/port-sockets.h @@ -157,6 +157,7 @@ typedef int socklen_t; #include #include /* For struct sockaddr_in and in_addr */ +#include /* For struct sockaddr_un */ #include /* For inet_ntoa */ #include #include /* For memset */ diff --git a/src/include/socket-utils.h b/src/include/socket-utils.h index d379b37e1b..177662c874 100644 --- a/src/include/socket-utils.h +++ b/src/include/socket-utils.h @@ -90,6 +90,16 @@ static inline struct sockaddr_in6 *ss2sin6 (struct sockaddr_storage *ss) { return (struct sockaddr_in6 *) ss; } +#ifndef _WIN32 +static inline const struct sockaddr_un *sa2sun(const struct sockaddr *sa) +{ + return (const struct sockaddr_un *)(void *)sa; +} +static inline struct sockaddr_un *ss2sun(struct sockaddr_storage *ss) +{ + return (struct sockaddr_un *)ss; +} +#endif /* Set the IPv4 or IPv6 port on sa to port. Do nothing if sa is not an * Internet socket. */ @@ -141,6 +151,10 @@ sa_socklen(const struct sockaddr *sa) return sizeof(struct sockaddr_in6); else if (sa->sa_family == AF_INET) return sizeof(struct sockaddr_in); +#ifndef _WIN32 + else if (sa->sa_family == AF_UNIX) + return sizeof(struct sockaddr_un); +#endif else abort(); } diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c index d366c050a2..5b73a3d8d2 100644 --- a/src/kadmin/server/schpw.c +++ b/src/kadmin/server/schpw.c @@ -40,7 +40,7 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm, const char *errmsg = NULL; size_t clen; char *cdots; - char addrbuf[100]; + char addrbuf[128]; *rep = empty_data(); @@ -286,8 +286,8 @@ chpwfail: cipher = empty_data(); if (ap_rep.length) { - if (k5_sockaddr_to_address(local_addr, &laddr) != 0) - abort(); + if (k5_sockaddr_to_address(local_addr, FALSE, &laddr) != 0) + laddr = k5_addr_directional_accept; ret = krb5_auth_con_setaddrs(context, auth_context, &laddr, NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c index 13d17b6d3a..46b1c8b440 100644 --- a/src/kdc/dispatch.c +++ b/src/kdc/dispatch.c @@ -116,7 +116,7 @@ dispatch(void *cb, const struct sockaddr *local_addr, if (kdc_check_lookaside(kdc_err_context, pkt, &response)) { /* a hit! */ const char *name = 0; - char buf[46]; + char buf[128]; k5_print_addr(remote_addr, buf, sizeof(buf)); if (name == 0) diff --git a/src/kdc/kdc_audit.c b/src/kdc/kdc_audit.c index a5e022489c..9ce8263d28 100644 --- a/src/kdc/kdc_audit.c +++ b/src/kdc/kdc_audit.c @@ -188,7 +188,7 @@ kau_init_kdc_req(krb5_context context, if (state == NULL) return ret; - ret = k5_sockaddr_to_address(from, &addr); + ret = k5_sockaddr_to_address(from, TRUE, &addr); if (ret) addr = unknown_addr; ret = krb5_copy_addr(context, &addr, &state->cl_addr); diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c index 6278d645a2..0291362d42 100644 --- a/src/kdc/kdc_log.c +++ b/src/kdc/kdc_log.c @@ -63,7 +63,7 @@ log_as_req(krb5_context context, krb5_timestamp authtime, const char *status, krb5_error_code errcode, const char *emsg) { - char fromstring[70]; + char fromstring[128]; char *ktypestr = NULL; const char *cname2 = cname ? cname : ""; const char *sname2 = sname ? sname : ""; @@ -88,8 +88,8 @@ log_as_req(krb5_context context, ktypestr ? ktypestr : "", fromstring, status, cname2, sname2, emsg ? ", " : "", emsg ? emsg : ""); } - (void)k5_sockaddr_to_address(local_addr, &laddr); - (void)k5_sockaddr_to_address(remote_addr, &raddr); + (void)k5_sockaddr_to_address(local_addr, TRUE, &laddr); + (void)k5_sockaddr_to_address(remote_addr, TRUE, &raddr); krb5_db_audit_as_req(context, request, &laddr, &raddr, client, server, authtime, errcode); @@ -123,7 +123,7 @@ log_tgs_req(krb5_context ctx, const struct sockaddr *from, const char *status, krb5_error_code errcode, const char *emsg) { char *ktypestr = NULL, *rep_etypestr = NULL; - char fromstring[70]; + char fromstring[128]; char *cname = NULL, *sname = NULL, *altcname = NULL; char *logcname = NULL, *logsname = NULL, *logaltcname = NULL; diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index b7249c083f..6f88afa2d7 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -194,7 +194,7 @@ kdc_process_tgs_req(kdc_realm_t *realm, krb5_kdc_req *request, /* If from_addr isn't IPv4 or IPv6, fake up an address that won't be * matched if the ticket has an address list. */ - retval = k5_sockaddr_to_address(from, &from_addr); + retval = k5_sockaddr_to_address(from, FALSE, &from_addr); if (retval) from_addr = nomatch_addr; retval = krb5_auth_con_setaddrs(context, auth_context, NULL, &from_addr); diff --git a/src/kprop/kprop.c b/src/kprop/kprop.c index cb5c5267a2..5adf430ac1 100644 --- a/src/kprop/kprop.c +++ b/src/kprop/kprop.c @@ -269,8 +269,8 @@ open_connection(krb5_context context, char *host, int *fd_out) com_err(progname, errno, _("while getting local socket address")); exit(1); } - if (k5_sockaddr_to_address(ss2sa(&my_sin), &addr) != 0) - abort(); + if (k5_sockaddr_to_address(ss2sa(&my_sin), FALSE, &addr) != 0) + addr = k5_addr_directional_init; retval = krb5_copy_addr(context, &addr, &sender_addr); if (retval) { com_err(progname, retval, _("while converting local address")); diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c index d6deb47382..4b36752646 100644 --- a/src/kprop/kpropd.c +++ b/src/kprop/kpropd.c @@ -1199,8 +1199,8 @@ kerberos_authenticate(krb5_context context, int fd, krb5_principal *clientp, exit(1); } - if (k5_sockaddr_to_address(ss2sa(my_sin), &addr) != 0) - abort(); + if (k5_sockaddr_to_address(ss2sa(my_sin), FALSE, &addr) != 0) + addr = k5_addr_directional_accept; retval = krb5_copy_addr(context, &addr, &receiver_addr); if (retval) { com_err(progname, retval, _("while converting local address")); diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c index 3713b50266..6fa8a97e03 100644 --- a/src/lib/apputils/net-server.c +++ b/src/lib/apputils/net-server.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef HAVE_SYS_SOCKIO_H /* for SIOCGIFCONF, etc. */ #include @@ -67,8 +68,8 @@ /* XXX */ #define KDC5_NONET (-1779992062L) -static int tcp_or_rpc_data_counter; -static int max_tcp_or_rpc_data_connections = 45; +static int stream_data_counter; +static int max_stream_data_connections = 45; static int setreuseaddr(int sock, int value) @@ -97,17 +98,29 @@ setv6only(int sock, int value) /* KDC data. */ enum conn_type { - CONN_UDP, CONN_TCP_LISTENER, CONN_TCP, CONN_RPC_LISTENER, CONN_RPC + CONN_UDP, CONN_TCP_LISTENER, CONN_TCP, CONN_RPC_LISTENER, CONN_RPC, + CONN_UNIXSOCK_LISTENER, CONN_UNIXSOCK +}; + +static const char *const conn_type_names[] = { + [CONN_UDP] = "UDP", + [CONN_TCP_LISTENER] = "TCP listener", + [CONN_TCP] = "TCP", + [CONN_RPC_LISTENER] = "RPC listener", + [CONN_RPC] = "RPC", + [CONN_UNIXSOCK_LISTENER] = "UNIX domain socket listener", + [CONN_UNIXSOCK] = "UNIX domain socket" }; enum bind_type { - UDP, TCP, RPC + UDP, TCP, RPC, UNX }; static const char *const bind_type_names[] = { [UDP] = "UDP", [TCP] = "TCP", [RPC] = "RPC", + [UNX] = "UNIXSOCK", }; /* Per-connection info. */ @@ -119,7 +132,7 @@ struct connection { /* Connection fields (TCP or RPC) */ struct sockaddr_storage addr_s; socklen_t addrlen; - char addrbuf[56]; + char addrbuf[128]; /* Incoming data (TCP) */ size_t bufsiz; @@ -262,10 +275,10 @@ loop_setup_signals(verto_ctx *ctx, void *handle, void (*reset)(void *)) * * Arguments: * - address - * A string for the address (or hostname). Pass NULL to use the wildcard - * address. The address is parsed with k5_parse_host_string(). + * An address string, hostname, or UNIX socket path. + * Pass NULL to use the wildcard address for IP sockets. * - port - * What port the socket should be set to. + * What port the socket should be set to (for IPv4 or IPv6). * - type * bind_type for the socket. * - rpc_data @@ -371,6 +384,19 @@ loop_add_addresses(const char *addresses, int default_port, /* Loop through each address in the string and add it to the loop. */ addr = strtok_r(addresses_copy, ADDRESSES_DELIM, &saveptr); for (; addr != NULL; addr = strtok_r(NULL, ADDRESSES_DELIM, &saveptr)) { + if (type == UNX) { + /* Skip non-pathnames when binding UNIX domain sockets. */ + if (*addr != '/') + continue; + ret = loop_add_address(addr, 0, type, rpc_data); + if (ret) + goto cleanup; + continue; + } else if (*addr == '/') { + /* Skip pathnames when not binding UNIX domain sockets. */ + continue; + } + /* Parse the host string. */ ret = k5_parse_host_string(addr, default_port, &host, &port); if (ret) @@ -416,6 +442,16 @@ loop_add_rpc_service(int default_port, const char *addresses, u_long prognum, return loop_add_addresses(addresses, default_port, RPC, &svc); } +krb5_error_code +loop_add_unix_socket(const char *socket_paths) +{ + /* There is no wildcard or default UNIX domain socket. */ + if (socket_paths == NULL) + return 0; + + return loop_add_addresses(socket_paths, 0, UNX, NULL); +} + #define USE_AF AF_INET #define USE_TYPE SOCK_DGRAM #define USE_PROTO 0 @@ -484,7 +520,8 @@ free_socket(verto_ctx *ctx, verto_ev *ev) } /* Fall through. */ case CONN_TCP: - tcp_or_rpc_data_counter--; + case CONN_UNIXSOCK: + stream_data_counter--; break; default: break; @@ -548,9 +585,9 @@ add_fd(int sock, enum conn_type conntype, verto_ev_flag flags, void *handle, } static void process_packet(verto_ctx *ctx, verto_ev *ev); -static void accept_tcp_connection(verto_ctx *ctx, verto_ev *ev); -static void process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev); -static void process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev); +static void accept_stream_connection(verto_ctx *ctx, verto_ev *ev); +static void process_stream_connection_read(verto_ctx *ctx, verto_ev *ev); +static void process_stream_connection_write(verto_ctx *ctx, verto_ev *ev); static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev); static void process_rpc_connection(verto_ctx *ctx, verto_ev *ev); @@ -568,6 +605,8 @@ create_server_socket(struct sockaddr *addr, int type, const char *prog, *fd_out = -1; + if (addr->sa_family == AF_UNIX) + (void)unlink(sa2sun(addr)->sun_path); sock = socket(addr->sa_family, type, 0); if (sock == -1) { e = errno; @@ -641,7 +680,8 @@ static const int bind_socktypes[] = { [UDP] = SOCK_DGRAM, [TCP] = SOCK_STREAM, - [RPC] = SOCK_STREAM + [RPC] = SOCK_STREAM, + [UNX] = SOCK_STREAM }; /* An enum map containing conn_type (for struct connection) for each @@ -650,7 +690,8 @@ static const enum conn_type bind_conn_types[] = { [UDP] = CONN_UDP, [TCP] = CONN_TCP_LISTENER, - [RPC] = CONN_RPC_LISTENER + [RPC] = CONN_RPC_LISTENER, + [UNX] = CONN_UNIXSOCK_LISTENER }; /* @@ -668,7 +709,7 @@ static const enum conn_type bind_conn_types[] = static krb5_error_code setup_socket(struct bind_address *ba, struct sockaddr *sock_address, void *handle, const char *prog, verto_ctx *ctx, - int tcp_listen_backlog, verto_callback vcb, enum conn_type ctype) + int listen_backlog, verto_callback vcb, enum conn_type ctype) { krb5_error_code ret; struct connection *conn; @@ -687,16 +728,17 @@ setup_socket(struct bind_address *ba, struct sockaddr *sock_address, if (ret) goto cleanup; - /* Listen for backlogged connections on TCP sockets. (For RPC sockets this - * will be done by svc_register().) */ - if (ba->type == TCP && listen(sock, tcp_listen_backlog) != 0) { + /* Listen for backlogged connections on stream sockets. (For RPC sockets + * this will be done by svc_register().) */ + if ((ba->type == TCP || ba->type == UNX) && + listen(sock, listen_backlog) != 0) { ret = errno; com_err(prog, errno, _("Cannot listen on %s server socket on %s"), bind_type_names[ba->type], addrbuf); goto cleanup; } - /* Set non-blocking I/O for UDP and TCP listener sockets. */ + /* Set non-blocking I/O for non-RPC listener sockets. */ if (ba->type != RPC && setnbio(sock) != 0) { ret = errno; com_err(prog, errno, @@ -780,18 +822,20 @@ cleanup: */ static krb5_error_code setup_addresses(verto_ctx *ctx, void *handle, const char *prog, - int tcp_listen_backlog) + int listen_backlog) { /* An bind_type enum map for the verto callback functions. */ static verto_callback *const verto_callbacks[] = { [UDP] = &process_packet, - [TCP] = &accept_tcp_connection, - [RPC] = &accept_rpc_connection + [TCP] = &accept_stream_connection, + [RPC] = &accept_rpc_connection, + [UNX] = &accept_stream_connection }; krb5_error_code ret = 0; size_t i; int err, bound_any; struct bind_address addr; + struct sockaddr_un sun; struct addrinfo hints, *ai_list = NULL, *ai = NULL; verto_callback vcb; char addrbuf[128]; @@ -816,6 +860,28 @@ setup_addresses(verto_ctx *ctx, void *handle, const char *prog, addr = bind_addresses.data[i]; hints.ai_socktype = bind_socktypes[addr.type]; + if (addr.type == UNX) { + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, addr.address, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) { + ret = ENAMETOOLONG; + krb5_klog_syslog(LOG_ERR, + _("UNIX domain socket path too long: %s"), + addr.address); + goto cleanup; + } + ret = setup_socket(&addr, (struct sockaddr *)&sun, handle, prog, + ctx, listen_backlog, verto_callbacks[addr.type], + bind_conn_types[addr.type]); + if (ret) { + krb5_klog_syslog(LOG_ERR, + _("Failed setting up a UNIX socket (for %s)"), + addr.address); + goto cleanup; + } + continue; + } + /* Call getaddrinfo, using a dummy port value. */ err = getaddrinfo(addr.address, "0", &hints, &ai_list); if (err) { @@ -846,7 +912,7 @@ setup_addresses(verto_ctx *ctx, void *handle, const char *prog, sa_setport(ai->ai_addr, addr.port); ret = setup_socket(&addr, ai->ai_addr, handle, prog, ctx, - tcp_listen_backlog, verto_callbacks[addr.type], + listen_backlog, verto_callbacks[addr.type], bind_conn_types[addr.type]); if (ret) { k5_print_addr(ai->ai_addr, addrbuf, sizeof(addrbuf)); @@ -876,7 +942,7 @@ cleanup: krb5_error_code loop_setup_network(verto_ctx *ctx, void *handle, const char *prog, - int tcp_listen_backlog) + int listen_backlog) { krb5_error_code ret; verto_ev *ev; @@ -892,7 +958,7 @@ loop_setup_network(verto_ctx *ctx, void *handle, const char *prog, events.n = 0; krb5_klog_syslog(LOG_INFO, _("setting up network...")); - ret = setup_addresses(ctx, handle, prog, tcp_listen_backlog); + ret = setup_addresses(ctx, handle, prog, listen_backlog); if (ret) { com_err(prog, ret, _("Error setting up network")); exit(1); @@ -1015,7 +1081,7 @@ process_packet(verto_ctx *ctx, verto_ev *ev) } static int -kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev) +kill_lru_stream_connection(void *handle, verto_ev *newev) { struct connection *c = NULL, *oldest_c = NULL; verto_ev *ev, *oldest_ev = NULL; @@ -1030,7 +1096,8 @@ kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev) c = verto_get_private(ev); if (!c) continue; - if (c->type != CONN_TCP && c->type != CONN_RPC) + if (c->type != CONN_TCP && c->type != CONN_RPC && + c->type != CONN_UNIXSOCK) continue; if (oldest_c == NULL || oldest_c->start_time > c->start_time) { @@ -1040,7 +1107,7 @@ kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev) } if (oldest_c != NULL) { krb5_klog_syslog(LOG_INFO, _("dropping %s fd %d from %s"), - oldest_c->type == CONN_RPC ? "rpc" : "tcp", + conn_type_names[oldest_c->type], verto_get_fd(oldest_ev), oldest_c->addrbuf); if (oldest_c->type == CONN_RPC) oldest_c->rpc_force_close = 1; @@ -1050,12 +1117,13 @@ kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev) } static void -accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) +accept_stream_connection(verto_ctx *ctx, verto_ev *ev) { int s; struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); struct connection *newconn, *conn; + enum conn_type ctype; verto_ev_flag flags; verto_ev *newev; @@ -1070,16 +1138,31 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) return; } #endif - setnbio(s), setnolinger(s), setkeepalive(s); + setnbio(s); + setnolinger(s); + if (addr.ss_family != AF_UNIX) + setkeepalive(s); flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST; - if (add_fd(s, CONN_TCP, flags, conn->handle, conn->prog, ctx, - process_tcp_connection_read, &newev) != 0) { + ctype = (conn->type == CONN_TCP_LISTENER) ? CONN_TCP : CONN_UNIXSOCK; + if (add_fd(s, ctype, flags, conn->handle, conn->prog, ctx, + process_stream_connection_read, &newev) != 0) { close(s); return; } newconn = verto_get_private(newev); + if (addr.ss_family == AF_UNIX) { + /* accept() doesn't fill in sun_path as the client socket isn't bound. + * For logging purposes we will use the target address. */ + addrlen = sizeof(addr); + if (getsockname(s, ss2sa(&addr), &addrlen) < 0) { + com_err(conn->prog, errno, _("Failed to get address for %d"), s); + close(s); + return; + } + } + k5_print_addr_port(ss2sa(&addr), newconn->addrbuf, sizeof(newconn->addrbuf)); newconn->addr_s = addr; @@ -1088,8 +1171,8 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) newconn->buffer = malloc(newconn->bufsiz); newconn->start_time = time(0); - if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections) - kill_lru_tcp_or_rpc_connection(conn->handle, newev); + if (++stream_data_counter > max_stream_data_connections) + kill_lru_stream_connection(conn->handle, newev); if (newconn->buffer == 0) { com_err(conn->prog, errno, @@ -1112,7 +1195,7 @@ struct tcp_dispatch_state { }; static void -process_tcp_response(void *arg, krb5_error_code code, krb5_data *response) +process_stream_response(void *arg, krb5_error_code code, krb5_data *response) { struct tcp_dispatch_state *state = arg; verto_ev *ev; @@ -1132,14 +1215,14 @@ process_tcp_response(void *arg, krb5_error_code code, krb5_data *response) state->conn->sgnum = 2; ev = make_event(state->ctx, VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST, - process_tcp_connection_write, state->sock, state->conn); + process_stream_connection_write, state->sock, state->conn); if (ev) { free(state); return; } kill_tcp_connection: - tcp_or_rpc_data_counter--; + stream_data_counter--; free_connection(state->conn); close(state->sock); free(state); @@ -1166,7 +1249,7 @@ prepare_for_dispatch(verto_ctx *ctx, verto_ev *ev) } static void -process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev) +process_stream_connection_read(verto_ctx *ctx, verto_ev *ev) { struct tcp_dispatch_state *state = NULL; struct connection *conn = NULL; @@ -1219,7 +1302,7 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev) krb5_free_data(get_context(conn->handle), response); goto kill_tcp_connection; } - process_tcp_response(state, 0, response); + process_stream_response(state, 0, response); } } } else { @@ -1253,7 +1336,7 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev) } dispatch(state->conn->handle, ss2sa(&state->local_saddr), ss2sa(&conn->addr_s), &state->request, 1, ctx, - process_tcp_response, state); + process_stream_response, state); } return; @@ -1263,7 +1346,7 @@ kill_tcp_connection: } static void -process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev) +process_stream_connection_write(verto_ctx *ctx, verto_ev *ev) { struct connection *conn; SOCKET_WRITEV_TEMP tmp; @@ -1377,8 +1460,8 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev) newconn->addrlen = addrlen; newconn->start_time = time(0); - if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections) - kill_lru_tcp_or_rpc_connection(newconn->handle, newev); + if (++stream_data_counter > max_stream_data_connections) + kill_lru_stream_connection(newconn->handle, newev); } } diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 63bc7a86c0..1e7076d3ce 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -119,6 +119,8 @@ initialize_prof_error_table k5_add_empty_pa_data k5_add_pa_data_element k5_add_pa_data_from_data +k5_addr_directional_accept +k5_addr_directional_init k5_alloc_pa_data k5_authind_decode k5_build_conf_principals diff --git a/src/lib/krb5/os/addr.c b/src/lib/krb5/os/addr.c index 1d8ae75013..e351ef800e 100644 --- a/src/lib/krb5/os/addr.c +++ b/src/lib/krb5/os/addr.c @@ -33,8 +33,16 @@ #include "k5-int.h" #include "socket-utils.h" +const krb5_address k5_addr_directional_init = { + KV5M_ADDRESS, ADDRTYPE_DIRECTIONAL, 4, (uint8_t *)"\x00\x00\x00\x00" +}; +const krb5_address k5_addr_directional_accept = { + KV5M_ADDRESS, ADDRTYPE_DIRECTIONAL, 4, (uint8_t *)"\x00\x00\x00\x01" +}; + krb5_error_code -k5_sockaddr_to_address(const struct sockaddr *sa, krb5_address *out) +k5_sockaddr_to_address(const struct sockaddr *sa, krb5_boolean local_use, + krb5_address *out) { if (sa->sa_family == AF_INET) { const struct sockaddr_in *sin = sa2sin(sa); @@ -52,6 +60,13 @@ k5_sockaddr_to_address(const struct sockaddr *sa, krb5_address *out) out->length = sizeof(sin6->sin6_addr); out->contents = (uint8_t *)&sin6->sin6_addr; } +#ifndef _WIN32 + } else if (sa->sa_family == AF_UNIX && local_use) { + const struct sockaddr_un *sun = sa2sun(sa); + out->addrtype = ADDRTYPE_UNIXSOCK; + out->length = strlen(sun->sun_path); + out->contents = (uint8_t *)sun->sun_path; +#endif } else { return KRB5_PROG_ATYPE_NOSUPP; } @@ -66,6 +81,10 @@ k5_print_addr(const struct sockaddr *sa, char *buf, size_t len) if (getnameinfo(sa, sa_socklen(sa), buf, len, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0) strlcpy(buf, "", len); +#ifndef _WIN32 + } else if (sa->sa_family == AF_UNIX) { + strlcpy(buf, sa2sun(sa)->sun_path, len); +#endif } else { strlcpy(buf, "", len); } diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c index bc132bc338..d32a12b630 100644 --- a/src/lib/krb5/os/changepw.c +++ b/src/lib/krb5/os/changepw.c @@ -143,6 +143,12 @@ kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message) local_kaddr.addrtype = ADDRTYPE_INET6; local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr); local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr; +#ifndef _WIN32 + } else if (local_addr.ss_family == AF_UNIX) { + /* There is no standard way to represent UNIX domain sockets. Assume + * that the receiver will accept a directional address. */ + local_kaddr = k5_addr_directional_init; +#endif } else { code = krb5_os_localaddr(ctx->context, &addrs); if (code) diff --git a/src/plugins/audit/j_dict.h b/src/plugins/audit/j_dict.h index 65962e331f..fd93ceb04b 100644 --- a/src/plugins/audit/j_dict.h +++ b/src/plugins/audit/j_dict.h @@ -45,6 +45,7 @@ #define AU_FROMADDR "fromaddr" #define AU_TYPE "type" /* used by fromaddr */ #define AU_IP "ip" /* used by fromaddr */ +#define AU_PATH "path" /* used by fromaddr */ #define AU_SESS_ETYPE "sess_etype" #define AU_SRV_ETYPE "srv_etype" #define AU_REP_ETYPE "rep_etype" diff --git a/src/plugins/audit/kdc_j_encode.c b/src/plugins/audit/kdc_j_encode.c index 0df258d766..31f308067f 100755 --- a/src/plugins/audit/kdc_j_encode.c +++ b/src/plugins/audit/kdc_j_encode.c @@ -630,6 +630,17 @@ addr_to_obj(krb5_address *a, k5_json_object obj) ret = k5_json_object_set(obj, AU_IP, arr); if (ret) goto error; + } else if (a->addrtype == ADDRTYPE_UNIXSOCK) { + k5_json_string str = NULL; + + ret = k5_json_string_create_len(a->contents, a->length, &str); + if (ret) + return ret; + + ret = k5_json_object_set(obj, AU_PATH, str); + k5_json_release(str); + if (ret) + goto error; } error: -- 2.47.3