diff options
Diffstat (limited to 'src/lib')
146 files changed, 1582 insertions, 1936 deletions
diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c index 29ec84a15b22..a40da927ef16 100644 --- a/src/lib/apputils/net-server.c +++ b/src/lib/apputils/net-server.c @@ -105,17 +105,6 @@ paddr(struct sockaddr *sa) return buf; } -/* Return true if sa is an IPv4 or IPv6 wildcard address. */ -static int -is_wildcard(struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET6) - return IN6_IS_ADDR_UNSPECIFIED(&sa2sin6(sa)->sin6_addr); - else if (sa->sa_family == AF_INET) - return sa2sin(sa)->sin_addr.s_addr == INADDR_ANY; - return 0; -} - /* KDC data. */ enum conn_type { @@ -142,8 +131,8 @@ struct connection { struct sockaddr_storage addr_s; socklen_t addrlen; char addrbuf[56]; - krb5_fulladdr faddr; - krb5_address kaddr; + krb5_address remote_addr_buf; + krb5_fulladdr remote_addr; /* Incoming data (TCP) */ size_t bufsiz; @@ -451,14 +440,6 @@ loop_add_rpc_service(int default_port, const char *addresses, u_long prognum, #define SOCKET_ERRNO errno #include "foreachaddr.h" -struct socksetup { - verto_ctx *ctx; - void *handle; - const char *prog; - krb5_error_code retval; - int listen_backlog; -}; - static void free_connection(struct connection *conn) { @@ -533,7 +514,7 @@ free_socket(verto_ctx *ctx, verto_ev *ev) static verto_ev * make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback, - int sock, struct connection *conn, int addevent) + int sock, struct connection *conn) { verto_ev *ev; void *tmp; @@ -544,45 +525,44 @@ make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback, return NULL; } - if (addevent) { - if (!ADD(events, ev, tmp)) { - com_err(conn->prog, ENOMEM, _("cannot save event")); - verto_del(ev); - return NULL; - } + if (!ADD(events, ev, tmp)) { + com_err(conn->prog, ENOMEM, _("cannot save event")); + verto_del(ev); + return NULL; } verto_set_private(ev, conn, free_socket); return ev; } -static verto_ev * -add_fd(struct socksetup *data, int sock, enum conn_type conntype, - verto_ev_flag flags, verto_callback callback, int addevent) +static krb5_error_code +add_fd(int sock, enum conn_type conntype, verto_ev_flag flags, void *handle, + const char *prog, verto_ctx *ctx, verto_callback callback, + verto_ev **ev_out) { struct connection *newconn; + *ev_out = NULL; + #ifndef _WIN32 if (sock >= FD_SETSIZE) { - data->retval = EMFILE; /* XXX */ - com_err(data->prog, 0, - _("file descriptor number %d too high"), sock); - return 0; + com_err(prog, 0, _("file descriptor number %d too high"), sock); + return EMFILE; } #endif newconn = malloc(sizeof(*newconn)); if (newconn == NULL) { - data->retval = ENOMEM; - com_err(data->prog, ENOMEM, + com_err(prog, ENOMEM, _("cannot allocate storage for connection info")); - return 0; + return ENOMEM; } memset(newconn, 0, sizeof(*newconn)); - newconn->handle = data->handle; - newconn->prog = data->prog; + newconn->handle = handle; + newconn->prog = prog; newconn->type = conntype; - return make_event(data->ctx, flags, callback, sock, newconn, addevent); + *ev_out = make_event(ctx, flags, callback, sock, newconn); + return 0; } static void process_packet(verto_ctx *ctx, verto_ev *ev); @@ -592,77 +572,62 @@ static void process_tcp_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); -static verto_ev * -add_tcp_read_fd(struct socksetup *data, int sock) -{ - return add_fd(data, sock, CONN_TCP, - VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST, - process_tcp_connection_read, 1); -} - /* * Create a socket and bind it to addr. Ensure the socket will work with * select(). Set the socket cloexec, reuseaddr, and if applicable v6-only. - * Does not call listen(). Returns -1 on failure after logging an error. + * Does not call listen(). On failure, log an error and return an error code. */ -static int -create_server_socket(struct socksetup *data, struct sockaddr *addr, int type) +static krb5_error_code +create_server_socket(struct sockaddr *addr, int type, const char *prog, + int *fd_out) { - int sock; + int sock, e; + + *fd_out = -1; sock = socket(addr->sa_family, type, 0); if (sock == -1) { - data->retval = errno; - com_err(data->prog, errno, _("Cannot create TCP server socket on %s"), + e = errno; + com_err(prog, e, _("Cannot create TCP server socket on %s"), paddr(addr)); - return -1; + return e; } set_cloexec_fd(sock); #ifndef _WIN32 /* Windows FD_SETSIZE is a count. */ if (sock >= FD_SETSIZE) { close(sock); - com_err(data->prog, 0, _("TCP socket fd number %d (for %s) too high"), + com_err(prog, 0, _("TCP socket fd number %d (for %s) too high"), sock, paddr(addr)); - return -1; + return EMFILE; } #endif - if (setreuseaddr(sock, 1) < 0) { - com_err(data->prog, errno, - _("Cannot enable SO_REUSEADDR on fd %d"), sock); - } + if (setreuseaddr(sock, 1) < 0) + com_err(prog, errno, _("Cannot enable SO_REUSEADDR on fd %d"), sock); if (addr->sa_family == AF_INET6) { #ifdef IPV6_V6ONLY - if (setv6only(sock, 1)) - com_err(data->prog, errno, - _("setsockopt(%d,IPV6_V6ONLY,1) failed"), sock); - else - com_err(data->prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"), + if (setv6only(sock, 1)) { + com_err(prog, errno, _("setsockopt(%d,IPV6_V6ONLY,1) failed"), sock); + } else { + com_err(prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"), sock); + } #else krb5_klog_syslog(LOG_INFO, _("no IPV6_V6ONLY socket option support")); #endif /* IPV6_V6ONLY */ } if (bind(sock, addr, sa_socklen(addr)) == -1) { - data->retval = errno; - com_err(data->prog, errno, _("Cannot bind server socket on %s"), - paddr(addr)); + e = errno; + com_err(prog, e, _("Cannot bind server socket on %s"), paddr(addr)); close(sock); - return -1; + return e; } - return sock; -} - -static verto_ev * -add_rpc_data_fd(struct socksetup *data, int sock) -{ - return add_fd(data, sock, CONN_RPC, - VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST, - process_rpc_connection, 1); + *fd_out = sock; + return 0; } static const int one = 1; @@ -716,12 +681,13 @@ static const enum conn_type bind_conn_types[] = * The conn_type of this socket. */ static krb5_error_code -setup_socket(struct socksetup *data, struct bind_address *ba, - struct sockaddr *sock_address, verto_callback vcb, - enum conn_type ctype) +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) { krb5_error_code ret; struct connection *conn; + verto_ev_flag flags; verto_ev *ev = NULL; int sock = -1; @@ -729,18 +695,16 @@ setup_socket(struct socksetup *data, struct bind_address *ba, bind_type_names[ba->type], paddr(sock_address)); /* Create the socket. */ - sock = create_server_socket(data, sock_address, bind_socktypes[ba->type]); - if (sock == -1) { - ret = data->retval; + ret = create_server_socket(sock_address, bind_socktypes[ba->type], prog, + &sock); + 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, data->listen_backlog) != 0) { + if (ba->type == TCP && listen(sock, tcp_listen_backlog) != 0) { ret = errno; - com_err(data->prog, errno, - _("Cannot listen on %s server socket on %s"), + com_err(prog, errno, _("Cannot listen on %s server socket on %s"), bind_type_names[ba->type], paddr(sock_address)); goto cleanup; } @@ -748,7 +712,7 @@ setup_socket(struct socksetup *data, struct bind_address *ba, /* Set non-blocking I/O for UDP and TCP listener sockets. */ if (ba->type != RPC && setnbio(sock) != 0) { ret = errno; - com_err(data->prog, errno, + com_err(prog, errno, _("cannot set listening %s socket on %s non-blocking"), bind_type_names[ba->type], paddr(sock_address)); goto cleanup; @@ -757,19 +721,18 @@ setup_socket(struct socksetup *data, struct bind_address *ba, /* Turn off the linger option for TCP sockets. */ if (ba->type == TCP && setnolinger(sock) != 0) { ret = errno; - com_err(data->prog, errno, - _("cannot set SO_LINGER on %s socket on %s"), + com_err(prog, errno, _("cannot set SO_LINGER on %s socket on %s"), bind_type_names[ba->type], paddr(sock_address)); goto cleanup; } /* Try to turn on pktinfo for UDP wildcard sockets. */ - if (ba->type == UDP && is_wildcard(sock_address)) { + if (ba->type == UDP && sa_is_wildcard(sock_address)) { krb5_klog_syslog(LOG_DEBUG, _("Setting pktinfo on socket %s"), paddr(sock_address)); ret = set_pktinfo(sock, sock_address->sa_family); if (ret) { - com_err(data->prog, ret, + com_err(prog, ret, _("Cannot request packet info for UDP socket address " "%s port %d"), paddr(sock_address), ba->port); krb5_klog_syslog(LOG_INFO, _("System does not support pktinfo yet " @@ -780,13 +743,11 @@ setup_socket(struct socksetup *data, struct bind_address *ba, } /* Add the socket to the event loop. */ - ev = add_fd(data, sock, ctype, - VERTO_EV_FLAG_IO_READ | - VERTO_EV_FLAG_PERSIST | - VERTO_EV_FLAG_REINITIABLE, vcb, 1); - if (ev == NULL) { + flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST | + VERTO_EV_FLAG_REINITIABLE; + ret = add_fd(sock, ctype, flags, handle, prog, ctx, vcb, &ev); + if (ret) { krb5_klog_syslog(LOG_ERR, _("Error attempting to add verto event")); - ret = data->retval; goto cleanup; } @@ -829,13 +790,10 @@ cleanup: * This function uses getaddrinfo to figure out all the addresses. This will * automatically figure out which socket families that should be used on the * host making it useful even for wildcard addresses. - * - * Arguments: - * - data - * A pointer to the socksetup data. */ static krb5_error_code -setup_addresses(struct socksetup *data) +setup_addresses(verto_ctx *ctx, void *handle, const char *prog, + int tcp_listen_backlog) { /* An bind_type enum map for the verto callback functions. */ static verto_callback *const verto_callbacks[] = { @@ -896,8 +854,8 @@ setup_addresses(struct socksetup *data) /* Set the real port number. */ sa_setport(ai->ai_addr, addr.port); - ret = setup_socket(data, &addr, ai->ai_addr, - verto_callbacks[addr.type], + ret = setup_socket(&addr, ai->ai_addr, handle, prog, ctx, + tcp_listen_backlog, verto_callbacks[addr.type], bind_conn_types[addr.type]); if (ret) { krb5_klog_syslog(LOG_ERR, @@ -929,9 +887,9 @@ krb5_error_code loop_setup_network(verto_ctx *ctx, void *handle, const char *prog, int tcp_listen_backlog) { - struct socksetup setup_data; + krb5_error_code ret; verto_ev *ev; - int i, ret; + int i; /* Check to make sure that at least one address was added to the loop. */ if (bind_addresses.n == 0) @@ -942,15 +900,9 @@ loop_setup_network(verto_ctx *ctx, void *handle, const char *prog, verto_del(ev); events.n = 0; - setup_data.ctx = ctx; - setup_data.handle = handle; - setup_data.prog = prog; - setup_data.retval = 0; - setup_data.listen_backlog = tcp_listen_backlog; - krb5_klog_syslog(LOG_INFO, _("setting up network...")); - ret = setup_addresses(&setup_data); - if (ret != 0) { + ret = setup_addresses(ctx, handle, prog, tcp_listen_backlog); + if (ret) { com_err(prog, ret, _("Error setting up network")); exit(1); } @@ -999,8 +951,10 @@ struct udp_dispatch_state { void *handle; const char *prog; int port_fd; - krb5_address addr; - krb5_fulladdr faddr; + krb5_address remote_addr_buf; + krb5_fulladdr remote_addr; + krb5_address local_addr_buf; + krb5_fulladdr local_addr; socklen_t saddr_len; socklen_t daddr_len; struct sockaddr_storage saddr; @@ -1132,10 +1086,15 @@ process_packet(verto_ctx *ctx, verto_ev *ev) state->request.length = cc; state->request.data = state->pktbuf; - state->faddr.address = &state->addr; - init_addr(&state->faddr, ss2sa(&state->saddr)); + + state->remote_addr.address = &state->remote_addr_buf; + init_addr(&state->remote_addr, ss2sa(&state->saddr)); + + state->local_addr.address = &state->local_addr_buf; + init_addr(&state->local_addr, ss2sa(&state->daddr)); + /* This address is in net order. */ - dispatch(state->handle, ss2sa(&state->daddr), &state->faddr, + dispatch(state->handle, &state->local_addr, &state->remote_addr, &state->request, 0, ctx, process_packet_response, state); } @@ -1186,9 +1145,9 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) struct sockaddr_storage addr_s; struct sockaddr *addr = (struct sockaddr *)&addr_s; socklen_t addrlen = sizeof(addr_s); - struct socksetup sockdata; struct connection *newconn, *conn; char tmpbuf[10]; + verto_ev_flag flags; verto_ev *newev; conn = verto_get_private(ev); @@ -1204,13 +1163,9 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) #endif setnbio(s), setnolinger(s), setkeepalive(s); - sockdata.ctx = ctx; - sockdata.handle = conn->handle; - sockdata.prog = conn->prog; - sockdata.retval = 0; - - newev = add_tcp_read_fd(&sockdata, s); - if (newev == NULL) { + 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) { close(s); return; } @@ -1253,14 +1208,16 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev) return; } newconn->offset = 0; - newconn->faddr.address = &newconn->kaddr; - init_addr(&newconn->faddr, ss2sa(&newconn->addr_s)); + newconn->remote_addr.address = &newconn->remote_addr_buf; + init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s)); SG_SET(&newconn->sgbuf[0], newconn->lenbuf, 4); SG_SET(&newconn->sgbuf[1], 0, 0); } struct tcp_dispatch_state { struct sockaddr_storage local_saddr; + krb5_address local_addr_buf; + krb5_fulladdr local_addr; struct connection *conn; krb5_data request; verto_ctx *ctx; @@ -1288,7 +1245,7 @@ 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, 1); + process_tcp_connection_write, state->sock, state->conn); if (ev) { free(state); return; @@ -1381,7 +1338,6 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev) } else { /* msglen known. */ socklen_t local_saddrlen = sizeof(struct sockaddr_storage); - struct sockaddr *local_saddrp = NULL; len = conn->msglen - (conn->offset - 4); nread = SOCKET_READ(verto_get_fd(ev), @@ -1403,10 +1359,14 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev) state->request.data = conn->buffer + 4; if (getsockname(verto_get_fd(ev), ss2sa(&state->local_saddr), - &local_saddrlen) == 0) - local_saddrp = ss2sa(&state->local_saddr); - - dispatch(state->conn->handle, local_saddrp, &conn->faddr, + &local_saddrlen) < 0) { + krb5_klog_syslog(LOG_ERR, _("getsockname failed: %s"), + error_message(errno)); + goto kill_tcp_connection; + } + state->local_addr.address = &state->local_addr_buf; + init_addr(&state->local_addr, ss2sa(&state->local_saddr)); + dispatch(state->conn->handle, &state->local_addr, &conn->remote_addr, &state->request, 1, ctx, process_tcp_response, state); } @@ -1489,18 +1449,13 @@ have_event_for_fd(int fd) static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev) { - struct socksetup sockdata; + verto_ev_flag flags; struct connection *conn; fd_set fds; register int s; conn = verto_get_private(ev); - sockdata.ctx = ctx; - sockdata.handle = conn->handle; - sockdata.prog = conn->prog; - sockdata.retval = 0; - /* Service the woken RPC listener descriptor. */ FD_ZERO(&fds); FD_SET(verto_get_fd(ev), &fds); @@ -1519,8 +1474,9 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev) if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s)) continue; - newev = add_rpc_data_fd(&sockdata, s); - if (newev == NULL) + flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST; + if (add_fd(s, CONN_RPC, flags, conn->handle, conn->prog, ctx, + process_rpc_connection, &newev) != 0) continue; newconn = verto_get_private(newev); @@ -1559,8 +1515,8 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev) if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections) kill_lru_tcp_or_rpc_connection(newconn->handle, newev); - newconn->faddr.address = &newconn->kaddr; - init_addr(&newconn->faddr, ss2sa(&newconn->addr_s)); + newconn->remote_addr.address = &newconn->remote_addr_buf; + init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s)); } } diff --git a/src/lib/apputils/udppktinfo.c b/src/lib/apputils/udppktinfo.c index bc7ad09b070c..c096c12b7e61 100644 --- a/src/lib/apputils/udppktinfo.c +++ b/src/lib/apputils/udppktinfo.c @@ -141,19 +141,17 @@ is_socket_bound_to_wildcard(int sock) { struct sockaddr_storage bound_addr; socklen_t bound_addr_len = sizeof(bound_addr); + struct sockaddr *sa = ss2sa(&bound_addr); - if (getsockname(sock, ss2sa(&bound_addr), &bound_addr_len) < 0) + if (getsockname(sock, sa, &bound_addr_len) < 0) return -1; - switch (ss2sa(&bound_addr)->sa_family) { - case AF_INET: - return ss2sin(&bound_addr)->sin_addr.s_addr == INADDR_ANY; - case AF_INET6: - return IN6_IS_ADDR_UNSPECIFIED(&ss2sin6(&bound_addr)->sin6_addr); - default: + if (!sa_is_inet(sa)) { errno = EINVAL; return -1; } + + return sa_is_wildcard(sa); } #ifdef HAVE_IP_PKTINFO @@ -402,7 +400,7 @@ set_msg_from_ipv6_pktinfo(struct msghdr *msg, struct cmsghdr *cmsgptr, /* * 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 + * macOS 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. diff --git a/src/lib/apputils/udppktinfo.h b/src/lib/apputils/udppktinfo.h index b0c7ea36b7b9..ff5759ab7ad3 100644 --- a/src/lib/apputils/udppktinfo.h +++ b/src/lib/apputils/udppktinfo.h @@ -32,7 +32,7 @@ * 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 + * In this case, we only need one datum so far: On macOS, the * kernel doesn't seem to like sending from link-local addresses * unless we specify the correct interface. */ diff --git a/src/lib/crypto/builtin/des/des_int.h b/src/lib/crypto/builtin/des/des_int.h index 0801cb5828c9..67e40a19ca32 100644 --- a/src/lib/crypto/builtin/des/des_int.h +++ b/src/lib/crypto/builtin/des/des_int.h @@ -74,7 +74,7 @@ #endif /* defined(__MACH__) && defined(__APPLE__) */ /* Macro to add deprecated attribute to DES types and functions */ -/* Currently only defined on Mac OS X 10.5 and later. */ +/* Currently only defined on macOS 10.5 and later. */ #ifndef KRB5INT_DES_DEPRECATED #define KRB5INT_DES_DEPRECATED #endif diff --git a/src/lib/crypto/builtin/des/destest.c b/src/lib/crypto/builtin/des/destest.c index 6eeb070d867f..dd2f68ec4032 100644 --- a/src/lib/crypto/builtin/des/destest.c +++ b/src/lib/crypto/builtin/des/destest.c @@ -52,6 +52,7 @@ /* Test a DES implementation against known inputs & outputs. */ #include "des_int.h" +#include <ctype.h> #include <stdio.h> void convert (char *, unsigned char []); @@ -160,7 +161,7 @@ convert(text, cblock) { register int i; for (i = 0; i < 8; i++) { - if (text[i*2] < 0 || text[i*2] >= 128) + if (!isascii((unsigned char)text[i * 2])) abort (); if (value[(int) text[i*2]] == -1 || value[(int) text[i*2+1]] == -1) { printf("Bad value byte %d in %s\n", i, text); diff --git a/src/lib/crypto/builtin/enc_provider/rc4.c b/src/lib/crypto/builtin/enc_provider/rc4.c index 3776f80715ab..df710489eaf0 100644 --- a/src/lib/crypto/builtin/enc_provider/rc4.c +++ b/src/lib/crypto/builtin/enc_provider/rc4.c @@ -113,7 +113,7 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data, return KRB5_BAD_MSIZE; if (state != NULL) { - cipher_state = (ArcFourCipherState *)state->data; + cipher_state = (ArcFourCipherState *)(void *)state->data; arcfour_ctx = &cipher_state->ctx; if (cipher_state->initialized == 0) { ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents, diff --git a/src/lib/crypto/builtin/sha2/sha256.c b/src/lib/crypto/builtin/sha2/sha256.c index e34bed575c5f..2b5cbe480503 100644 --- a/src/lib/crypto/builtin/sha2/sha256.c +++ b/src/lib/crypto/builtin/sha2/sha256.c @@ -211,14 +211,14 @@ k5_sha256_update(SHA256_CTX *m, const void *v, size_t len) #if !defined(WORDS_BIGENDIAN) || defined(_CRAY) int i; uint32_t current[16]; - struct x32 *u = (struct x32*)m->save; + struct x32 *u = (struct x32*)(void*)m->save; for(i = 0; i < 8; i++){ current[2*i+0] = swap_uint32_t(u[i].a); current[2*i+1] = swap_uint32_t(u[i].b); } calc(m, current); #else - calc(m, (uint32_t*)m->save); + calc(m, (uint32_t*)(void*)m->save); #endif offset = 0; } diff --git a/src/lib/crypto/builtin/sha2/sha512.c b/src/lib/crypto/builtin/sha2/sha512.c index 8f0ce894033f..6130655576c9 100644 --- a/src/lib/crypto/builtin/sha2/sha512.c +++ b/src/lib/crypto/builtin/sha2/sha512.c @@ -217,14 +217,14 @@ k5_sha512_update (SHA512_CTX *m, const void *v, size_t len) #if !defined(WORDS_BIGENDIAN) || defined(_CRAY) int i; uint64_t current[16]; - struct x64 *us = (struct x64*)m->save; + struct x64 *us = (struct x64*)(void*)m->save; for(i = 0; i < 8; i++){ current[2*i+0] = swap_uint64_t(us[i].a); current[2*i+1] = swap_uint64_t(us[i].b); } calc(m, current); #else - calc(m, (uint64_t*)m->save); + calc(m, (uint64_t*)(void*)m->save); #endif offset = 0; } diff --git a/src/lib/crypto/krb/Makefile.in b/src/lib/crypto/krb/Makefile.in index c5660c5fe1fa..fc01a2ced4ae 100644 --- a/src/lib/crypto/krb/Makefile.in +++ b/src/lib/crypto/krb/Makefile.in @@ -212,7 +212,7 @@ depend: $(SRCS) check-unix: t_fortuna if [ $(PRNG_ALG) = fortuna ]; then \ - $(RUN_TEST) ./t_fortuna > t_fortuna.output; \ + $(RUN_TEST) ./t_fortuna > t_fortuna.output && \ cmp t_fortuna.output $(srcdir)/t_fortuna.expected; \ fi diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h index d75b49c693f0..e5099291e309 100644 --- a/src/lib/crypto/krb/crypto_int.h +++ b/src/lib/crypto/krb/crypto_int.h @@ -111,6 +111,7 @@ struct krb5_keytypes { prf_func prf; krb5_cksumtype required_ctype; krb5_flags flags; + unsigned int ssf; }; #define ETYPE_WEAK 1 diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c index 0ed74bd6ebde..b1b40e7ecd6e 100644 --- a/src/lib/crypto/krb/enctype_util.c +++ b/src/lib/crypto/krb/enctype_util.c @@ -131,3 +131,19 @@ krb5_enctype_to_name(krb5_enctype enctype, krb5_boolean shortest, return ENOMEM; return 0; } + +/* The security of a mechanism cannot be summarized with a simple integer + * value, but we provide a per-enctype value for Cyrus SASL's SSF. */ +krb5_error_code +k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out) +{ + const struct krb5_keytypes *ktp; + + *ssf_out = 0; + + ktp = find_enctype(enctype); + if (ktp == NULL) + return EINVAL; + *ssf_out = ktp->ssf; + return 0; +} diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c index 0e5e977d418a..53d4a5c79b47 100644 --- a/src/lib/crypto/krb/etypes.c +++ b/src/lib/crypto/krb/etypes.c @@ -42,7 +42,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_des_string_to_key, k5_rand2key_des, krb5int_des_prf, CKSUMTYPE_RSA_MD5_DES, - ETYPE_WEAK }, + ETYPE_WEAK, 56 }, { ENCTYPE_DES_CBC_MD4, "des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4", &krb5int_enc_des, &krb5int_hash_md4, @@ -51,7 +51,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_des_string_to_key, k5_rand2key_des, krb5int_des_prf, CKSUMTYPE_RSA_MD4_DES, - ETYPE_WEAK }, + ETYPE_WEAK, 56 }, { ENCTYPE_DES_CBC_MD5, "des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5", &krb5int_enc_des, &krb5int_hash_md5, @@ -60,7 +60,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_des_string_to_key, k5_rand2key_des, krb5int_des_prf, CKSUMTYPE_RSA_MD5_DES, - ETYPE_WEAK }, + ETYPE_WEAK, 56 }, { ENCTYPE_DES_CBC_RAW, "des-cbc-raw", { 0 }, "DES cbc mode raw", &krb5int_enc_des, NULL, @@ -69,7 +69,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_des_string_to_key, k5_rand2key_des, krb5int_des_prf, 0, - ETYPE_WEAK }, + ETYPE_WEAK, 56 }, { ENCTYPE_DES3_CBC_RAW, "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw", &krb5int_enc_des3, NULL, @@ -78,7 +78,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_dk_string_to_key, k5_rand2key_des3, NULL, /*PRF*/ 0, - ETYPE_WEAK }, + ETYPE_WEAK, 112 }, { ENCTYPE_DES3_CBC_SHA1, "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" }, @@ -89,7 +89,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_dk_string_to_key, k5_rand2key_des3, krb5int_dk_prf, CKSUMTYPE_HMAC_SHA1_DES3, - 0 /*flags*/ }, + 0 /*flags*/, 112 }, { ENCTYPE_DES_HMAC_SHA1, "des-hmac-sha1", { 0 }, "DES with HMAC/sha1", @@ -99,7 +99,10 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_dk_string_to_key, k5_rand2key_des, NULL, /*PRF*/ 0, - ETYPE_WEAK }, + ETYPE_WEAK, 56 }, + + /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we + * consider its strength degraded and assign it an SSF value of 64. */ { ENCTYPE_ARCFOUR_HMAC, "arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" }, "ArcFour with HMAC/md5", @@ -110,7 +113,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key, k5_rand2key_direct, krb5int_arcfour_prf, CKSUMTYPE_HMAC_MD5_ARCFOUR, - 0 /*flags*/ }, + 0 /*flags*/, 64 }, { ENCTYPE_ARCFOUR_HMAC_EXP, "arcfour-hmac-exp", { "rc4-hmac-exp", "arcfour-hmac-md5-exp" }, "Exportable ArcFour with HMAC/md5", @@ -121,7 +124,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key, k5_rand2key_direct, krb5int_arcfour_prf, CKSUMTYPE_HMAC_MD5_ARCFOUR, - ETYPE_WEAK + ETYPE_WEAK, 40 }, { ENCTYPE_AES128_CTS_HMAC_SHA1_96, @@ -133,7 +136,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_aes_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_HMAC_SHA1_96_AES128, - 0 /*flags*/ }, + 0 /*flags*/, 128 }, { ENCTYPE_AES256_CTS_HMAC_SHA1_96, "aes256-cts-hmac-sha1-96", { "aes256-cts", "aes256-sha1" }, "AES-256 CTS mode with 96-bit SHA-1 HMAC", @@ -143,7 +146,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_aes_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_HMAC_SHA1_96_AES256, - 0 /*flags*/ }, + 0 /*flags*/, 256 }, { ENCTYPE_CAMELLIA128_CTS_CMAC, "camellia128-cts-cmac", { "camellia128-cts" }, @@ -155,7 +158,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_camellia_string_to_key, k5_rand2key_direct, krb5int_dk_cmac_prf, CKSUMTYPE_CMAC_CAMELLIA128, - 0 /*flags*/ }, + 0 /*flags*/, 128 }, { ENCTYPE_CAMELLIA256_CTS_CMAC, "camellia256-cts-cmac", { "camellia256-cts" }, "Camellia-256 CTS mode with CMAC", @@ -166,7 +169,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_camellia_string_to_key, k5_rand2key_direct, krb5int_dk_cmac_prf, CKSUMTYPE_CMAC_CAMELLIA256, - 0 /*flags */ }, + 0 /*flags */, 256 }, { ENCTYPE_AES128_CTS_HMAC_SHA256_128, "aes128-cts-hmac-sha256-128", { "aes128-sha2" }, @@ -177,7 +180,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_HMAC_SHA256_128_AES128, - 0 /*flags*/ }, + 0 /*flags*/, 128 }, { ENCTYPE_AES256_CTS_HMAC_SHA384_192, "aes256-cts-hmac-sha384-192", { "aes256-sha2" }, "AES-256 CTS mode with 192-bit SHA-384 HMAC", @@ -187,7 +190,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_HMAC_SHA384_192_AES256, - 0 /*flags*/ }, + 0 /*flags*/, 256 }, }; const int krb5int_enctypes_length = diff --git a/src/lib/crypto/krb/s2k_des.c b/src/lib/crypto/krb/s2k_des.c index 31a613bebc61..d5c29befcb2e 100644 --- a/src/lib/crypto/krb/s2k_des.c +++ b/src/lib/crypto/krb/s2k_des.c @@ -509,7 +509,7 @@ des_s2k(const krb5_data *pw, const krb5_data *salt, unsigned char *key_out) #define FETCH4(VAR, IDX) VAR = temp.ui[IDX/4] #define PUT4(VAR, IDX) temp.ui[IDX/4] = VAR - copylen = pw->length + (salt ? salt->length : 0); + copylen = pw->length + salt->length; /* Don't need NUL termination, at this point we're treating it as a byte array, not a string. */ copy = malloc(copylen); @@ -517,7 +517,7 @@ des_s2k(const krb5_data *pw, const krb5_data *salt, unsigned char *key_out) return ENOMEM; if (pw->length > 0) memcpy(copy, pw->data, pw->length); - if (salt != NULL && salt->length > 0) + if (salt->length > 0) memcpy(copy + pw->length, salt->data, salt->length); memset(&temp, 0, sizeof(temp)); diff --git a/src/lib/crypto/krb/s2k_pbkdf2.c b/src/lib/crypto/krb/s2k_pbkdf2.c index ec5856c2be79..1fea03408c76 100644 --- a/src/lib/crypto/krb/s2k_pbkdf2.c +++ b/src/lib/crypto/krb/s2k_pbkdf2.c @@ -47,7 +47,7 @@ krb5int_dk_string_to_key(const struct krb5_keytypes *ktp, keybytes = ktp->enc->keybytes; keylength = ktp->enc->keylength; - concatlen = string->length + (salt ? salt->length : 0); + concatlen = string->length + salt->length; concat = k5alloc(concatlen, &ret); if (ret != 0) @@ -63,7 +63,7 @@ krb5int_dk_string_to_key(const struct krb5_keytypes *ktp, if (string->length > 0) memcpy(concat, string->data, string->length); - if (salt != NULL && salt->length > 0) + if (salt->length > 0) memcpy(concat + string->length, salt->data, salt->length); krb5int_nfold(concatlen*8, concat, keybytes*8, foldstring); diff --git a/src/lib/crypto/krb/s2k_rc4.c b/src/lib/crypto/krb/s2k_rc4.c index 49ad89d323b0..081a91217c69 100644 --- a/src/lib/crypto/krb/s2k_rc4.c +++ b/src/lib/crypto/krb/s2k_rc4.c @@ -10,6 +10,7 @@ krb5int_arcfour_string_to_key(const struct krb5_keytypes *ktp, krb5_error_code err = 0; krb5_crypto_iov iov; krb5_data hash_out; + char *utf8; unsigned char *copystr; size_t copystrlen; @@ -20,8 +21,11 @@ krb5int_arcfour_string_to_key(const struct krb5_keytypes *ktp, return (KRB5_BAD_MSIZE); /* We ignore salt per the Microsoft spec. */ - err = krb5int_utf8cs_to_ucs2les(string->data, string->length, ©str, - ©strlen); + utf8 = k5memdup0(string->data, string->length, &err); + if (utf8 == NULL) + return err; + err = k5_utf8_to_utf16le(utf8, ©str, ©strlen); + free(utf8); if (err) return err; diff --git a/src/lib/crypto/krb/string_to_key.c b/src/lib/crypto/krb/string_to_key.c index b55ee75d2f34..352a8e8dcce2 100644 --- a/src/lib/crypto/krb/string_to_key.c +++ b/src/lib/crypto/krb/string_to_key.c @@ -43,6 +43,7 @@ krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype, const krb5_data *params, krb5_keyblock *key) { krb5_error_code ret; + krb5_data empty = empty_data(); const struct krb5_keytypes *ktp; size_t keylength; @@ -51,8 +52,12 @@ krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype, return KRB5_BAD_ENCTYPE; keylength = ktp->enc->keylength; + /* For compatibility with past behavior, treat a null salt as empty. */ + if (salt == NULL) + salt = ∅ + /* Fail gracefully if someone is using the old AFS string-to-key hack. */ - if (salt != NULL && salt->length == SALT_TYPE_AFS_LENGTH) + if (salt->length == SALT_TYPE_AFS_LENGTH) return EINVAL; key->contents = malloc(keylength); diff --git a/src/lib/crypto/krb/t_fortuna.c b/src/lib/crypto/krb/t_fortuna.c index 4f25bee62cb5..508ffcf915c7 100644 --- a/src/lib/crypto/krb/t_fortuna.c +++ b/src/lib/crypto/krb/t_fortuna.c @@ -85,7 +85,7 @@ head_tail_test(struct fortuna_state *st) { static unsigned char buffer[1024 * 1024]; unsigned char c; - size_t i, len = sizeof(buffer); + int i, len = sizeof(buffer); int bit, bits[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; double res; diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports index 447e45644453..82eb5f30c031 100644 --- a/src/lib/crypto/libk5crypto.exports +++ b/src/lib/crypto/libk5crypto.exports @@ -108,3 +108,4 @@ krb5int_nfold k5_allow_weak_pbkdf2iter krb5_c_prfplus krb5_c_derive_prfplus +k5_enctype_to_ssf diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h index 9ad44216d05e..9d3a7e736736 100644 --- a/src/lib/gssapi/generic/gssapi_ext.h +++ b/src/lib/gssapi/generic/gssapi_ext.h @@ -575,4 +575,15 @@ gss_import_cred( } #endif +/* + * When used with gss_inquire_sec_context_by_oid(), return a buffer set with + * the first member containing an unsigned 32-bit integer in network byte + * order. This is the Security Strength Factor (SSF) associated with the + * secure channel established by the security context. NOTE: This value is + * made available solely as an indication for use by APIs like Cyrus SASL that + * classify the strength of a secure channel via this number. The strength of + * a channel cannot necessarily be represented by a simple number. + */ +GSS_DLLIMP extern gss_OID GSS_C_SEC_CONTEXT_SASL_SSF; + #endif /* GSSAPI_EXT_H_ */ diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c index 5496aa33582c..fa144c2bf9cc 100644 --- a/src/lib/gssapi/generic/gssapi_generic.c +++ b/src/lib/gssapi/generic/gssapi_generic.c @@ -157,6 +157,13 @@ static const gss_OID_desc const_oids[] = { {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"}, {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"}, {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"}, + + /* + * GSS_SEC_CONTEXT_SASL_SSF_OID 1.2.840.113554.1.2.2.5.15 + * iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) krb5(2) krb5-gssapi-ext(5) sasl-ssf(15) + */ + {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"}, }; /* Here are the constants which point to the static structure above. @@ -218,6 +225,8 @@ GSS_DLLIMP gss_const_OID GSS_C_MA_PFS = oids+33; GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS = oids+34; GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS = oids+35; +GSS_DLLIMP gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = oids+36; + static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 }; gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc; diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index 580d08cbf53e..06967aa2753a 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -351,8 +351,10 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle, if (mech_type) *mech_type = ctx->mech_used; - if (time_rec) - *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now; + if (time_rec) { + *time_rec = ts_delta(ctx->krb_times.endtime, now) + + ctx->k5_context->clockskew; + } /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential * delegation yet. */ @@ -1146,7 +1148,7 @@ kg_accept_krb5(minor_status, context_handle, /* Add the maximum allowable clock skew as a grace period for context * expiration, just as we do for the ticket. */ if (time_rec) - *time_rec = ctx->krb_times.endtime + context->clockskew - now; + *time_rec = ts_delta(ctx->krb_times.endtime, now) + context->clockskew; if (ret_flags) *ret_flags = ctx->gss_flags; diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index 03ee25ec1861..362ba9d86a42 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -550,7 +550,7 @@ set_refresh_time(krb5_context context, krb5_ccache ccache, char buf[128]; krb5_data d; - snprintf(buf, sizeof(buf), "%ld", (long)refresh_time); + snprintf(buf, sizeof(buf), "%u", (unsigned int)ts2tt(refresh_time)); d = string2data(buf); (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME, &d); @@ -566,8 +566,9 @@ kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred) if (krb5_timeofday(context, &now)) return FALSE; - if (cred->refresh_time != 0 && now >= cred->refresh_time) { - set_refresh_time(context, cred->ccache, cred->refresh_time + 30); + if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) { + set_refresh_time(context, cred->ccache, + ts_incr(cred->refresh_time, 30)); return TRUE; } return FALSE; @@ -586,7 +587,8 @@ kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred, return; /* Make a note to refresh these when they are halfway to expired. */ - refresh = times->starttime + (times->endtime - times->starttime) / 2; + refresh = ts_incr(times->starttime, + ts_delta(times->endtime, times->starttime) / 2); set_refresh_time(context, cred->ccache, refresh); } @@ -848,7 +850,8 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status, GSS_C_NO_NAME); if (GSS_ERROR(ret)) goto error_out; - *time_rec = (cred->expire > now) ? (cred->expire - now) : 0; + *time_rec = ts_after(cred->expire, now) ? + ts_delta(cred->expire, now) : 0; k5_mutex_unlock(&cred->lock); } } diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c index a18cfb05b743..1fdb5a16f2b4 100644 --- a/src/lib/gssapi/krb5/context_time.c +++ b/src/lib/gssapi/krb5/context_time.c @@ -51,7 +51,10 @@ krb5_gss_context_time(minor_status, context_handle, time_rec) return(GSS_S_FAILURE); } - if ((lifetime = ctx->krb_times.endtime - now) <= 0) { + lifetime = ts_delta(ctx->krb_times.endtime, now); + if (!ctx->initiate) + lifetime += ctx->k5_context->clockskew; + if (lifetime <= 0) { *time_rec = 0; *minor_status = 0; return(GSS_S_CONTEXT_EXPIRED); diff --git a/src/lib/gssapi/krb5/copy_ccache.c b/src/lib/gssapi/krb5/copy_ccache.c index f3d7666135cd..027ed4847476 100644 --- a/src/lib/gssapi/krb5/copy_ccache.c +++ b/src/lib/gssapi/krb5/copy_ccache.c @@ -8,8 +8,6 @@ gss_krb5int_copy_ccache(OM_uint32 *minor_status, const gss_buffer_t value) { krb5_gss_cred_id_t k5creds; - krb5_cc_cursor cursor; - krb5_creds creds; krb5_error_code code; krb5_context context; krb5_ccache out_ccache; @@ -37,7 +35,7 @@ gss_krb5int_copy_ccache(OM_uint32 *minor_status, return GSS_S_FAILURE; } - code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor); + code = krb5_cc_copy_creds(context, k5creds->ccache, out_ccache); if (code) { k5_mutex_unlock(&k5creds->lock); *minor_status = code; @@ -45,12 +43,6 @@ gss_krb5int_copy_ccache(OM_uint32 *minor_status, krb5_free_context(context); return(GSS_S_FAILURE); } - while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor, - &creds)) { - code = krb5_cc_store_cred(context, out_ccache, &creds); - krb5_free_cred_contents(context, &creds); - } - krb5_cc_end_seq_get(context, k5creds->ccache, &cursor); k5_mutex_unlock(&k5creds->lock); *minor_status = code; if (code) diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c index 652b2604bda3..8054e4a77011 100644 --- a/src/lib/gssapi/krb5/export_cred.c +++ b/src/lib/gssapi/krb5/export_cred.c @@ -410,10 +410,11 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred, if (ret) goto cleanup; - ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp, + ret = k5_json_array_fmt(&array, "ivvbbvvvvbLLvs", cred->usage, name, imp, cred->default_identity, cred->iakerb_mech, keytab, rcache, ccache, ckeytab, cred->have_tgt, - cred->expire, cred->refresh_time, etypes, + (long long)ts2tt(cred->expire), + (long long)ts2tt(cred->refresh_time), etypes, cred->password); if (ret) goto cleanup; diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index d7bdef7e28a3..e92be88b4730 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -1144,6 +1144,12 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *, const gss_OID, gss_buffer_set_t *); +#define GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH 11 +#define GET_SEC_CONTEXT_SASL_SSF_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f" +OM_uint32 +gss_krb5int_sec_context_sasl_ssf(OM_uint32 *, const gss_ctx_id_t, + const gss_OID, gss_buffer_set_t *); + #define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11 #define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d" @@ -1425,4 +1431,10 @@ iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle, * the format changes. */ #define CRED_EXPORT_MAGIC "K5C1" +OM_uint32 +gss_krb5int_get_cred_impersonator(OM_uint32 *minor_status, + const gss_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set); + #endif /* _GSSAPIP_KRB5_H_ */ diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index 99092ccab16b..43930dd61aa6 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -126,6 +126,8 @@ #define NO_CI_FLAGS_X_OID_LENGTH 6 #define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d" +#define GET_CRED_IMPERSONATOR_OID_LENGTH 11 +#define GET_CRED_IMPERSONATOR_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e" const gss_OID_desc krb5_gss_oid_array[] = { /* this is the official, rfc-specified OID */ @@ -148,6 +150,8 @@ const gss_OID_desc krb5_gss_oid_array[] = { /* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */ {10, "\052\206\110\206\367\022\001\002\002\002"}, {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID}, + /* this is an inquire cred OID */ + {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID}, { 0, 0 } }; @@ -164,6 +168,7 @@ const gss_OID gss_nt_krb5_principal = &kg_oids[6]; const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &kg_oids[5]; const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X = &kg_oids[7]; +const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR = &kg_oids[8]; static const gss_OID_set_desc oidsets[] = { {1, &kg_oids[0]}, /* RFC OID */ @@ -352,6 +357,10 @@ static struct { { {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID}, gss_krb5int_extract_authtime_from_sec_context + }, + { + {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID}, + gss_krb5int_sec_context_sasl_ssf } }; @@ -400,13 +409,16 @@ krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, /* * gss_inquire_cred_by_oid() methods */ -#if 0 + static struct { gss_OID_desc oid; OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *); } krb5_gss_inquire_cred_by_oid_ops[] = { + { + {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID}, + gss_krb5int_get_cred_impersonator + } }; -#endif static OM_uint32 KRB5_CALLCONV krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status, @@ -415,9 +427,7 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status, gss_buffer_set_t *data_set) { OM_uint32 major_status = GSS_S_FAILURE; -#if 0 size_t i; -#endif if (minor_status == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; @@ -440,7 +450,6 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status, if (GSS_ERROR(major_status)) return major_status; -#if 0 for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/ sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) { if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) { @@ -450,7 +459,6 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status, data_set); } } -#endif *minor_status = EINVAL; diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h index 390b00032cce..e145eec3b44c 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.h +++ b/src/lib/gssapi/krb5/gssapi_krb5.h @@ -96,6 +96,15 @@ GSS_DLLIMP extern const gss_OID_desc krb5_gss_oid_array[]; */ GSS_DLLIMP extern const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X; +/* + * This OID can be used with gss_inquire_cred_by_oid(0 to retrieve the + * impersonator name (if any). + * + * iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * krb5(2) krb5-gssapi-ext(5) get-cred-impersonator(14) + */ +GSS_DLLIMP extern const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR; + #define gss_krb5_nt_general_name gss_nt_krb5_name #define gss_krb5_nt_principal gss_nt_krb5_principal #define gss_krb5_nt_service_name gss_nt_service_name @@ -169,6 +178,11 @@ OM_uint32 KRB5_CALLCONV gss_krb5_get_tkt_flags( gss_ctx_id_t context_handle, krb5_flags *ticket_flags); +/* + * Copy krb5 creds from cred_handle into out_ccache, which must already be + * initialized. Use gss_store_cred_into() (new in krb5 1.11) instead, if + * possible. + */ OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache( OM_uint32 *minor_status, gss_cred_id_t cred_handle, diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c index 2dc4d0c1a4d5..bb1072fe4ac7 100644 --- a/src/lib/gssapi/krb5/iakerb.c +++ b/src/lib/gssapi/krb5/iakerb.c @@ -494,7 +494,7 @@ iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx, if (code != 0) goto cleanup; - creds.times.endtime = now + time_req; + creds.times.endtime = ts_incr(now, time_req); } if (cred->name->ad_context != NULL) { @@ -669,7 +669,7 @@ iakerb_get_initial_state(iakerb_ctx_id_t ctx, if (code != 0) goto cleanup; - in_creds.times.endtime = now + time_req; + in_creds.times.endtime = ts_incr(now, time_req); } /* Make an AS request if we have no creds or it's time to refresh them. */ diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 70f7955ae1ae..1be1b5878400 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -214,7 +214,8 @@ static krb5_error_code get_credentials(context, cred, server, now, * boundaries) because accept_sec_context code is also similarly * non-forgiving. */ - if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) { + if (!krb5_gss_dbg_client_expcreds && + ts_after(now, result_creds->times.endtime)) { code = KRB5KRB_AP_ERR_TKT_EXPIRED; goto cleanup; } @@ -355,9 +356,6 @@ make_gss_checksum (krb5_context context, krb5_auth_context auth_context, TWRITE_STR(ptr, data->md5.contents, data->md5.length); TWRITE_INT(ptr, data->ctx->gss_flags, 0); - /* done with this, free it */ - xfree(data->md5.contents); - if (credmsg.data) { TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0); TWRITE_INT16(ptr, credmsg.length, 0); @@ -429,6 +427,7 @@ make_ap_req_v1(context, ctx, cred, k_cred, ad_context, code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags, NULL, k_cred, &ap_req); krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL); + krb5_free_checksum_contents(context, &cksum_struct.md5); krb5_free_data_contents(context, &cksum_struct.checksum_data); if (code) goto cleanup; @@ -575,7 +574,7 @@ kg_new_connection( if (time_req == 0 || time_req == GSS_C_INDEFINITE) { ctx->krb_times.endtime = 0; } else { - ctx->krb_times.endtime = now + time_req; + ctx->krb_times.endtime = ts_incr(now, time_req); } if ((code = kg_duplicate_name(context, cred->name, &ctx->here))) @@ -659,7 +658,7 @@ kg_new_connection( if (time_rec) { if ((code = krb5_timeofday(context, &now))) goto cleanup; - *time_rec = ctx->krb_times.endtime - now; + *time_rec = ts_delta(ctx->krb_times.endtime, now); } /* set the other returns */ @@ -873,7 +872,7 @@ mutual_auth( if (time_rec) { if ((code = krb5_timeofday(context, &now))) goto fail; - *time_rec = ctx->krb_times.endtime - now; + *time_rec = ts_delta(ctx->krb_times.endtime, now); } if (ret_flags) diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c index 9024b3c7ea9c..cac024da1f01 100644 --- a/src/lib/gssapi/krb5/inq_context.c +++ b/src/lib/gssapi/krb5/inq_context.c @@ -120,7 +120,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name, /* Add the maximum allowable clock skew as a grace period for context * expiration, just as we do for the ticket during authentication. */ - lifetime = ctx->krb_times.endtime - now; + lifetime = ts_delta(ctx->krb_times.endtime, now); if (!ctx->initiate) lifetime += context->clockskew; if (lifetime < 0) @@ -310,3 +310,30 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status, return generic_gss_add_buffer_set_member(minor_status, &rep, data_set); } + +OM_uint32 +gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_gss_ctx_id_rec *ctx; + krb5_key key; + krb5_error_code code; + gss_buffer_desc ssfbuf; + unsigned int ssf; + uint8_t buf[4]; + + ctx = (krb5_gss_ctx_id_rec *)context_handle; + key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey; + + code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf); + if (code) + return GSS_S_FAILURE; + + store_32_be(ssf, buf); + ssfbuf.value = buf; + ssfbuf.length = sizeof(buf); + + return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set); +} diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index 4e35a056316f..3a73417c083d 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -130,8 +130,9 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, goto fail; } - if (cred->expire > 0) { - if ((lifetime = cred->expire - now) < 0) + if (cred->expire != 0) { + lifetime = ts_delta(cred->expire, now); + if (lifetime < 0) lifetime = 0; } else @@ -245,3 +246,44 @@ krb5_gss_inquire_cred_by_mech(minor_status, cred_handle, } return(mstat); } + +OM_uint32 +gss_krb5int_get_cred_impersonator(OM_uint32 *minor_status, + const gss_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle; + gss_buffer_desc rep = GSS_C_EMPTY_BUFFER; + krb5_context context = NULL; + char *impersonator = NULL; + krb5_error_code ret; + OM_uint32 major; + + *data_set = GSS_C_NO_BUFFER_SET; + + /* Return an empty buffer set if no impersonator is present */ + if (cred->impersonator == NULL) + return generic_gss_create_empty_buffer_set(minor_status, data_set); + + ret = krb5_gss_init_context(&context); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_unparse_name(context, cred->impersonator, &impersonator); + if (ret) { + krb5_free_context(context); + *minor_status = ret; + return GSS_S_FAILURE; + } + + rep.value = impersonator; + rep.length = strlen(impersonator); + major = generic_gss_add_buffer_set_member(minor_status, &rep, data_set); + + krb5_free_unparsed_name(context, impersonator); + krb5_free_context(context); + return major; +} diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c index 1a5c14c2713b..25d9f2711825 100644 --- a/src/lib/gssapi/krb5/k5sealv3.c +++ b/src/lib/gssapi/krb5/k5sealv3.c @@ -110,6 +110,7 @@ gss_krb5int_make_seal_token_v3 (krb5_context context, krb5_data plain; krb5_enc_data cipher; size_t ec_max; + size_t encrypt_size; /* 300: Adds some slop. */ if (SIZE_MAX - 300 < message->length) @@ -128,7 +129,12 @@ gss_krb5int_make_seal_token_v3 (krb5_context context, return err; /* Get size of ciphertext. */ - bufsize = 16 + krb5_encrypt_size (plain.length, key->keyblock.enctype); + encrypt_size = krb5_encrypt_size(plain.length, key->keyblock.enctype); + if (encrypt_size > SIZE_MAX / 2) { + err = ENOMEM; + goto error; + } + bufsize = 16 + encrypt_size; /* Allocate space for header plus encrypted data. */ outbuf = gssalloc_malloc(bufsize); if (outbuf == NULL) { @@ -301,7 +307,7 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr, int *conf_state, gss_qop_t *qop_state, int toktype) { krb5_context context = *contextptr; - krb5_data plain; + krb5_data plain = empty_data(); uint64_t seqnum; size_t ec, rrc; int key_usage; diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c index 26a2d33e7a2c..57720c2eab98 100644 --- a/src/lib/gssapi/krb5/k5unseal.c +++ b/src/lib/gssapi/krb5/k5unseal.c @@ -219,7 +219,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, plainlen = tmsglen; conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype); - if (tmsglen < conflen) { + if (tmsglen < (size_t)conflen) { if (sealalg != 0xffff) xfree(plain); *minor_status = 0; diff --git a/src/lib/gssapi/krb5/naming_exts.c b/src/lib/gssapi/krb5/naming_exts.c index 6062a6dd8052..5f00efe346e3 100644 --- a/src/lib/gssapi/krb5/naming_exts.c +++ b/src/lib/gssapi/krb5/naming_exts.c @@ -261,8 +261,7 @@ krb5_gss_inquire_name(OM_uint32 *minor_status, krb5_gss_name_t kname; krb5_data *kattrs = NULL; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; if (attrs != NULL) *attrs = GSS_C_NO_BUFFER_SET; @@ -319,11 +318,10 @@ krb5_gss_get_name_attribute(OM_uint32 *minor_status, krb5_data kattr; krb5_boolean kauthenticated; krb5_boolean kcomplete; - krb5_data kvalue; - krb5_data kdisplay_value; + krb5_data kvalue = empty_data(); + krb5_data kdisplay_value = empty_data(); - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { @@ -355,8 +353,8 @@ krb5_gss_get_name_attribute(OM_uint32 *minor_status, &kattr, &kauthenticated, &kcomplete, - value ? &kvalue : NULL, - display_value ? &kdisplay_value : NULL, + &kvalue, + &kdisplay_value, more); if (code == 0) { if (value != NULL) @@ -367,14 +365,13 @@ krb5_gss_get_name_attribute(OM_uint32 *minor_status, if (complete != NULL) *complete = kcomplete; - if (display_value != NULL) { - if (code == 0) - code = data_to_gss(&kdisplay_value, display_value); - else - free(kdisplay_value.data); - } + if (display_value != NULL && code == 0) + code = data_to_gss(&kdisplay_value, display_value); } + free(kdisplay_value.data); + free(kvalue.data); + k5_mutex_unlock(&kname->lock); krb5_free_context(context); @@ -394,8 +391,7 @@ krb5_gss_set_name_attribute(OM_uint32 *minor_status, krb5_data kattr; krb5_data kvalue; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { @@ -444,8 +440,7 @@ krb5_gss_delete_name_attribute(OM_uint32 *minor_status, krb5_gss_name_t kname; krb5_data kattr; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { @@ -491,8 +486,7 @@ krb5_gss_map_name_to_any(OM_uint32 *minor_status, krb5_gss_name_t kname; char *kmodule; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { @@ -543,8 +537,7 @@ krb5_gss_release_any_name_mapping(OM_uint32 *minor_status, krb5_gss_name_t kname; char *kmodule; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { @@ -599,8 +592,7 @@ krb5_gss_export_name_composite(OM_uint32 *minor_status, unsigned char *cp; size_t princlen; - if (minor_status != NULL) - *minor_status = 0; + *minor_status = 0; code = krb5_gss_init_context(&context); if (code != 0) { diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c index ff1c310bce5e..10848c1df810 100644 --- a/src/lib/gssapi/krb5/s4u_gss_glue.c +++ b/src/lib/gssapi/krb5/s4u_gss_glue.c @@ -284,7 +284,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, if (code != 0) goto cleanup; - *time_rec = cred->expire - now; + *time_rec = ts_delta(cred->expire, now); } major_status = GSS_S_COMPLETE; diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports index 9facb3f42671..b07f69fd1572 100644 --- a/src/lib/gssapi/libgssapi_krb5.exports +++ b/src/lib/gssapi/libgssapi_krb5.exports @@ -10,6 +10,7 @@ GSS_C_NT_STRING_UID_NAME GSS_C_NT_USER_NAME GSS_KRB5_NT_PRINCIPAL_NAME GSS_KRB5_CRED_NO_CI_FLAGS_X +GSS_KRB5_GET_CRED_IMPERSONATOR GSS_C_MA_MECH_CONCRETE GSS_C_MA_MECH_PSEUDO GSS_C_MA_MECH_COMPOSITE @@ -37,6 +38,7 @@ GSS_C_MA_CBINDINGS GSS_C_MA_PFS GSS_C_MA_COMPRESS GSS_C_MA_CTX_TRANS +GSS_C_SEC_CONTEXT_SASL_SSF gss_accept_sec_context gss_acquire_cred gss_acquire_cred_with_password diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c index ddaf87412e9e..f28e2b14a903 100644 --- a/src/lib/gssapi/mechglue/g_accept_sec_context.c +++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c @@ -216,6 +216,8 @@ gss_cred_id_t * d_cred; } else { union_ctx_id = (gss_union_ctx_id_t)*context_handle; selected_mech = union_ctx_id->mech_type; + if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); } /* Now create a new context if we didn't get one. */ @@ -234,9 +236,6 @@ gss_cred_id_t * d_cred; free(union_ctx_id); return (status); } - - /* set the new context handle to caller's data */ - *context_handle = (gss_ctx_id_t)union_ctx_id; } /* @@ -277,8 +276,10 @@ gss_cred_id_t * d_cred; d_cred ? &tmp_d_cred : NULL); /* If there's more work to do, keep going... */ - if (status == GSS_S_CONTINUE_NEEDED) + if (status == GSS_S_CONTINUE_NEEDED) { + *context_handle = (gss_ctx_id_t)union_ctx_id; return GSS_S_CONTINUE_NEEDED; + } /* if the call failed, return with failure */ if (status != GSS_S_COMPLETE) { @@ -364,14 +365,22 @@ gss_cred_id_t * d_cred; *mech_type = gssint_get_public_oid(actual_mech); if (ret_flags != NULL) *ret_flags = temp_ret_flags; - return (status); + *context_handle = (gss_ctx_id_t)union_ctx_id; + return GSS_S_COMPLETE; } else { status = GSS_S_BAD_MECH; } error_out: - if (union_ctx_id) { + /* + * RFC 2744 5.1 requires that we not create a context on a failed first + * call to accept, and recommends that on a failed subsequent call we + * make the caller responsible for calling gss_delete_sec_context. + * Even if the mech deleted its context, keep the union context around + * for the caller to delete. + */ + if (union_ctx_id && *context_handle == GSS_C_NO_CONTEXT) { if (union_ctx_id->mech_type) { if (union_ctx_id->mech_type->elements) free(union_ctx_id->mech_type->elements); @@ -384,7 +393,6 @@ error_out: GSS_C_NO_BUFFER); } free(union_ctx_id); - *context_handle = GSS_C_NO_CONTEXT; } if (src_name) diff --git a/src/lib/gssapi/mechglue/g_complete_auth_token.c b/src/lib/gssapi/mechglue/g_complete_auth_token.c index 91815513017f..4bcb47e84b90 100644 --- a/src/lib/gssapi/mechglue/g_complete_auth_token.c +++ b/src/lib/gssapi/mechglue/g_complete_auth_token.c @@ -52,6 +52,8 @@ gss_complete_auth_token (OM_uint32 *minor_status, */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; mech = gssint_get_mechanism (ctx->mech_type); if (mech != NULL) { diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c index 2ff8d0996ef0..c947e7646c10 100644 --- a/src/lib/gssapi/mechglue/g_context_time.c +++ b/src/lib/gssapi/mechglue/g_context_time.c @@ -58,6 +58,8 @@ OM_uint32 * time_rec; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c index 4bf0dec5ce33..574ff02944b0 100644 --- a/src/lib/gssapi/mechglue/g_delete_sec_context.c +++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c @@ -87,12 +87,14 @@ gss_buffer_t output_token; if (GSSINT_CHK_LOOP(ctx)) return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT); - status = gssint_delete_internal_sec_context(minor_status, - ctx->mech_type, - &ctx->internal_ctx_id, - output_token); - if (status) - return status; + if (ctx->internal_ctx_id != GSS_C_NO_CONTEXT) { + status = gssint_delete_internal_sec_context(minor_status, + ctx->mech_type, + &ctx->internal_ctx_id, + output_token); + if (status) + return status; + } /* now free up the space for the union context structure */ free(ctx->mech_type->elements); diff --git a/src/lib/gssapi/mechglue/g_dup_name.c b/src/lib/gssapi/mechglue/g_dup_name.c index 85306fcc1913..cc824fdf99b8 100644 --- a/src/lib/gssapi/mechglue/g_dup_name.c +++ b/src/lib/gssapi/mechglue/g_dup_name.c @@ -126,7 +126,7 @@ allocation_failure: if (dest_union->external_name) { if (dest_union->external_name->value) free(dest_union->external_name->value); - free(dest_union->external_name); + free(dest_union->external_name); } if (dest_union->name_type) (void) generic_gss_release_oid(minor_status, diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c index b63745299f64..1d7990b1ca28 100644 --- a/src/lib/gssapi/mechglue/g_exp_sec_context.c +++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c @@ -95,6 +95,8 @@ gss_buffer_t interprocess_token; */ ctx = (gss_union_ctx_id_t) *context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (!mech) return GSS_S_BAD_MECH; diff --git a/src/lib/gssapi/mechglue/g_glue.c b/src/lib/gssapi/mechglue/g_glue.c index 4aa3591a0d06..4cd2e8f8eb8c 100644 --- a/src/lib/gssapi/mechglue/g_glue.c +++ b/src/lib/gssapi/mechglue/g_glue.c @@ -189,7 +189,7 @@ OM_uint32 gssint_get_mech_type_oid(OID, token) gss_buffer_t token; { unsigned char * buffer_ptr; - int length; + size_t buflen, lenbytes, length, oidlen; /* * This routine reads the prefix of "token" in order to determine @@ -223,25 +223,33 @@ OM_uint32 gssint_get_mech_type_oid(OID, token) /* Skip past the APP/Sequnce byte and the token length */ buffer_ptr = (unsigned char *) token->value; + buflen = token->length; - if (*(buffer_ptr++) != 0x60) + if (buflen < 2 || *buffer_ptr++ != 0x60) return (GSS_S_DEFECTIVE_TOKEN); length = *buffer_ptr++; + buflen -= 2; /* check if token length is null */ if (length == 0) return (GSS_S_DEFECTIVE_TOKEN); if (length & 0x80) { - if ((length & 0x7f) > 4) + lenbytes = length & 0x7f; + if (lenbytes > 4 || lenbytes > buflen) return (GSS_S_DEFECTIVE_TOKEN); - buffer_ptr += length & 0x7f; + buffer_ptr += lenbytes; + buflen -= lenbytes; } - if (*(buffer_ptr++) != 0x06) + if (buflen < 2 || *buffer_ptr++ != 0x06) + return (GSS_S_DEFECTIVE_TOKEN); + oidlen = *buffer_ptr++; + buflen -= 2; + if (oidlen > 0x7f || oidlen > buflen) return (GSS_S_DEFECTIVE_TOKEN); - OID->length = (OM_uint32) *(buffer_ptr++); + OID->length = oidlen; OID->elements = (void *) buffer_ptr; return (GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c index 9f154b8936d0..e2df1ce261d7 100644 --- a/src/lib/gssapi/mechglue/g_init_sec_context.c +++ b/src/lib/gssapi/mechglue/g_init_sec_context.c @@ -192,8 +192,13 @@ OM_uint32 * time_rec; /* copy the supplied context handle */ union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT; - } else + } else { union_ctx_id = (gss_union_ctx_id_t)*context_handle; + if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) { + status = GSS_S_NO_CONTEXT; + goto end; + } + } /* * get the appropriate cred handle from the union cred struct. @@ -224,15 +229,13 @@ OM_uint32 * time_rec; if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) { /* - * The spec says the preferred method is to delete all context info on - * the first call to init, and on all subsequent calls make the caller - * responsible for calling gss_delete_sec_context. However, if the - * mechanism decided to delete the internal context, we should also - * delete the union context. + * RFC 2744 5.19 requires that we not create a context on a failed + * first call to init, and recommends that on a failed subsequent call + * we make the caller responsible for calling gss_delete_sec_context. + * Even if the mech deleted its context, keep the union context around + * for the caller to delete. */ map_error(minor_status, mech); - if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) - *context_handle = GSS_C_NO_CONTEXT; if (*context_handle == GSS_C_NO_CONTEXT) { free(union_ctx_id->mech_type->elements); free(union_ctx_id->mech_type); diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c index 6f1c71eede9d..6c0d98dd3348 100644 --- a/src/lib/gssapi/mechglue/g_inq_context.c +++ b/src/lib/gssapi/mechglue/g_inq_context.c @@ -104,6 +104,8 @@ gss_inquire_context( */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (!mech || !mech->gss_inquire_context || !mech->gss_display_name || diff --git a/src/lib/gssapi/mechglue/g_inq_cred_oid.c b/src/lib/gssapi/mechglue/g_inq_cred_oid.c index 4c23dfcbd364..df51b44e9a5b 100644 --- a/src/lib/gssapi/mechglue/g_inq_cred_oid.c +++ b/src/lib/gssapi/mechglue/g_inq_cred_oid.c @@ -85,11 +85,6 @@ gss_inquire_cred_by_oid(OM_uint32 *minor_status, union_cred = (gss_union_cred_t) cred_handle; - status = gss_create_empty_buffer_set(minor_status, &ret_set); - if (status != GSS_S_COMPLETE) { - return status; - } - status = GSS_S_UNAVAILABLE; for (i = 0; i < union_cred->count; i++) { diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c index fcca3e44c4c0..9e168adfe0d6 100644 --- a/src/lib/gssapi/mechglue/g_prf.c +++ b/src/lib/gssapi/mechglue/g_prf.c @@ -59,6 +59,8 @@ gss_pseudo_random (OM_uint32 *minor_status, */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; mech = gssint_get_mechanism (ctx->mech_type); if (mech != NULL) { diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c index bc260aeb10b2..3968b5d9c675 100644 --- a/src/lib/gssapi/mechglue/g_process_context.c +++ b/src/lib/gssapi/mechglue/g_process_context.c @@ -61,6 +61,8 @@ gss_buffer_t token_buffer; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c index f17241c90891..3db1ee095b39 100644 --- a/src/lib/gssapi/mechglue/g_seal.c +++ b/src/lib/gssapi/mechglue/g_seal.c @@ -92,6 +92,8 @@ gss_wrap( OM_uint32 *minor_status, */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -226,6 +228,8 @@ gss_wrap_size_limit(OM_uint32 *minor_status, */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (!mech) diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c index 86d641aa2e28..03fbd8c01f36 100644 --- a/src/lib/gssapi/mechglue/g_sign.c +++ b/src/lib/gssapi/mechglue/g_sign.c @@ -94,6 +94,8 @@ gss_buffer_t msg_token; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c index 3e8053c6e9af..c208635b676a 100644 --- a/src/lib/gssapi/mechglue/g_unseal.c +++ b/src/lib/gssapi/mechglue/g_unseal.c @@ -76,6 +76,8 @@ gss_qop_t * qop_state; * call it. */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { diff --git a/src/lib/gssapi/mechglue/g_unwrap_aead.c b/src/lib/gssapi/mechglue/g_unwrap_aead.c index e78bff2d3289..0682bd899820 100644 --- a/src/lib/gssapi/mechglue/g_unwrap_aead.c +++ b/src/lib/gssapi/mechglue/g_unwrap_aead.c @@ -186,6 +186,8 @@ gss_qop_t *qop_state; * call it. */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (!mech) diff --git a/src/lib/gssapi/mechglue/g_unwrap_iov.c b/src/lib/gssapi/mechglue/g_unwrap_iov.c index c0dd314b1be8..599be2c7b2fc 100644 --- a/src/lib/gssapi/mechglue/g_unwrap_iov.c +++ b/src/lib/gssapi/mechglue/g_unwrap_iov.c @@ -89,6 +89,8 @@ int iov_count; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -128,6 +130,8 @@ gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, /* Select the approprate underlying mechanism routine and call it. */ ctx = (gss_union_ctx_id_t)context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; mech = gssint_get_mechanism(ctx->mech_type); if (mech == NULL) return GSS_S_BAD_MECH; diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c index 1578ae111092..8996fce8d596 100644 --- a/src/lib/gssapi/mechglue/g_verify.c +++ b/src/lib/gssapi/mechglue/g_verify.c @@ -65,6 +65,8 @@ gss_qop_t * qop_state; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { diff --git a/src/lib/gssapi/mechglue/g_wrap_aead.c b/src/lib/gssapi/mechglue/g_wrap_aead.c index 96cdf3ce6ab8..7fe3b7b35bda 100644 --- a/src/lib/gssapi/mechglue/g_wrap_aead.c +++ b/src/lib/gssapi/mechglue/g_wrap_aead.c @@ -256,6 +256,8 @@ gss_buffer_t output_message_buffer; * call it. */ ctx = (gss_union_ctx_id_t)context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (!mech) return (GSS_S_BAD_MECH); diff --git a/src/lib/gssapi/mechglue/g_wrap_iov.c b/src/lib/gssapi/mechglue/g_wrap_iov.c index 40cd98fc91cd..14447c4ee1ad 100644 --- a/src/lib/gssapi/mechglue/g_wrap_iov.c +++ b/src/lib/gssapi/mechglue/g_wrap_iov.c @@ -93,6 +93,8 @@ int iov_count; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -151,6 +153,8 @@ int iov_count; */ ctx = (gss_union_ctx_id_t) context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return (GSS_S_NO_CONTEXT); mech = gssint_get_mechanism (ctx->mech_type); if (mech) { @@ -190,6 +194,8 @@ gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, /* Select the approprate underlying mechanism routine and call it. */ ctx = (gss_union_ctx_id_t)context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; mech = gssint_get_mechanism(ctx->mech_type); if (mech == NULL) return GSS_S_BAD_MECH; @@ -218,6 +224,8 @@ gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle, /* Select the approprate underlying mechanism routine and call it. */ ctx = (gss_union_ctx_id_t)context_handle; + if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; mech = gssint_get_mechanism(ctx->mech_type); if (mech == NULL) return GSS_S_BAD_MECH; diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def index 362b9bce848f..842f3d52f3cd 100644 --- a/src/lib/gssapi32.def +++ b/src/lib/gssapi32.def @@ -182,3 +182,6 @@ EXPORTS gss_verify_mic_iov @146 ; Added in 1.14 GSS_KRB5_CRED_NO_CI_FLAGS_X @147 DATA +; Added in 1.16 + GSS_KRB5_GET_CRED_IMPERSONATOR @148 DATA + GSS_C_SEC_CONTEXT_SASL_SSF @149 DATA diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c index 408b0eb31fac..1680a5504922 100644 --- a/src/lib/kadm5/chpass_util.c +++ b/src/lib/kadm5/chpass_util.c @@ -4,15 +4,11 @@ */ -#include "autoconf.h" -#include <stdio.h> -#include <time.h> -#include <string.h> +#include "k5-int.h" #include <kadm5/admin.h> #include "admin_internal.h" -#include <krb5.h> #define string_text error_message @@ -218,7 +214,7 @@ kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, time_t until; char *time_string, *ptr; - until = princ_ent.last_pwd_change + policy_ent.pw_min_life; + until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life); time_string = ctime(&until); if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') diff --git a/src/lib/kadm5/deps b/src/lib/kadm5/deps index c9f0cbfdb7e2..3585f08f6442 100644 --- a/src/lib/kadm5/deps +++ b/src/lib/kadm5/deps @@ -42,13 +42,21 @@ chpass_util.so chpass_util.po $(OUTPRE)chpass_util.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ - $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/gssrpc/auth.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(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/kdb.h \ - $(top_srcdir)/include/krb5.h admin_internal.h chpass_util.c + $(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/k5-trace.h \ + $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + admin_internal.h chpass_util.c alt_prof.so alt_prof.po $(OUTPRE)alt_prof.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et index 71b053460117..892a6fac1053 100644 --- a/src/lib/kadm5/kadm_err.et +++ b/src/lib/kadm5/kadm_err.et @@ -66,4 +66,5 @@ error_code KADM5_BAD_KEYSALTS, "Invalid key/salt tuples" error_code KADM5_SETKEY_BAD_KVNO, "Invalid multiple or duplicate kvnos in setkey operation" error_code KADM5_AUTH_EXTRACT, "Operation requires ``extract-keys'' privilege" error_code KADM5_PROTECT_KEYS, "Principal keys are locked down" +error_code KADM5_AUTH_INITIAL, "Operation requires initial ticket" end diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in index f4b5b5b6a06d..617d6566665f 100644 --- a/src/lib/kadm5/srv/Makefile.in +++ b/src/lib/kadm5/srv/Makefile.in @@ -32,7 +32,6 @@ SRCS = $(srcdir)/pwqual.c \ $(srcdir)/pwqual_princ.c \ $(srcdir)/svr_policy.c \ $(srcdir)/svr_principal.c \ - $(srcdir)/server_acl.c \ $(srcdir)/server_kdb.c \ $(srcdir)/server_misc.c \ $(srcdir)/server_init.c \ @@ -48,7 +47,6 @@ OBJS = pwqual.$(OBJEXT) \ kadm5_hook.$(OBJEXT) \ svr_policy.$(OBJEXT) \ svr_principal.$(OBJEXT) \ - server_acl.$(OBJEXT) \ server_kdb.$(OBJEXT) \ server_misc.$(OBJEXT) \ server_init.$(OBJEXT) \ @@ -65,7 +63,6 @@ STLIBOBJS = \ kadm5_hook.o \ svr_policy.o \ svr_principal.o \ - server_acl.o \ server_kdb.o \ server_misc.o \ server_init.o \ @@ -73,23 +70,10 @@ STLIBOBJS = \ svr_chpass_util.o \ adb_xdr.o -all-unix: includes all-unix: all-liblinks all-windows: $(OBJS) -generate-files-mac: includes darwin.exports - -includes: server_acl.h - if cmp $(srcdir)/server_acl.h \ - $(BUILDTOP)/include/kadm5/server_acl.h >/dev/null 2>&1; then :; \ - else \ - (set -x; $(RM) $(BUILDTOP)/include/kadm5/server_acl.h; \ - $(CP) $(srcdir)/server_acl.h \ - $(BUILDTOP)/include/kadm5/server_acl.h) ; \ - fi - -clean-unix:: - $(RM) $(BUILDTOP)/include/kadm5/server_acl.h +generate-files-mac: darwin.exports check-windows: @@ -104,8 +88,6 @@ install-unix: (cd $(DESTDIR)$(KRB5_LIBDIR) && $(LN_S) lib$(LIBBASE)$(DEPLIBEXT) \ libkadm5srv$(DEPLIBEXT)) -depend: includes - @lib_frag@ @libobj_frag@ diff --git a/src/lib/kadm5/srv/deps b/src/lib/kadm5/srv/deps index 20df4e9b8205..01080d56053e 100644 --- a/src/lib/kadm5/srv/deps +++ b/src/lib/kadm5/srv/deps @@ -150,27 +150,6 @@ svr_principal.so svr_principal.po $(OUTPRE)svr_principal.$(OBJEXT): \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/kadm5_hook_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h svr_principal.c -server_acl.so server_acl.po $(OUTPRE)server_acl.$(OBJEXT): \ - $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ - $(BUILDTOP)/include/gssapi/gssapi_generic.h $(BUILDTOP)/include/gssrpc/types.h \ - $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \ - $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \ - $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \ - $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ - $(COM_ERR_DEPS) $(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 \ - $(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/k5-trace.h \ - $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - server_acl.c server_acl.h server_kdb.so server_kdb.po $(OUTPRE)server_kdb.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \ diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports index aedfdd7f5813..804eba16abb8 100644 --- a/src/lib/kadm5/srv/libkadm5srv_mit.exports +++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports @@ -1,10 +1,5 @@ _kadm5_check_handle _kadm5_chpass_principal_util -kadm5int_acl_check -kadm5int_acl_check_krb -kadm5int_acl_finish -kadm5int_acl_impose_restrictions -kadm5int_acl_init hist_princ kadm5_set_use_password_server kadm5_chpass_principal diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c deleted file mode 100644 index 59ed0b975472..000000000000 --- a/src/lib/kadm5/srv/server_acl.c +++ /dev/null @@ -1,823 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/kadm5/srv/server_acl.c */ -/* - * Copyright 1995-2004, 2007, 2008 by the Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * 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. - */ - -#include "k5-int.h" -#include <syslog.h> -#include <sys/param.h> -#include <gssapi/gssapi_generic.h> -#include <kadm5/server_internal.h> -#include <kadm5/admin.h> -#include "adm_proto.h" -#include "server_acl.h" -#include <ctype.h> - -typedef struct _acl_op_table { - char ao_op; - krb5_int32 ao_mask; -} aop_t; - -typedef struct _acl_entry { - struct _acl_entry *ae_next; - char *ae_name; - krb5_boolean ae_name_bad; - krb5_principal ae_principal; - krb5_int32 ae_op_allowed; - char *ae_target; - krb5_boolean ae_target_bad; - krb5_principal ae_target_princ; - char *ae_restriction_string; - /* eg: "-maxlife 3h -service +proxiable" */ - krb5_boolean ae_restriction_bad; - restriction_t *ae_restrictions; -} aent_t; - -static const aop_t acl_op_table[] = { - { 'a', ACL_ADD }, - { 'd', ACL_DELETE }, - { 'm', ACL_MODIFY }, - { 'c', ACL_CHANGEPW }, - { 'i', ACL_INQUIRE }, - { 'l', ACL_LIST }, - { 'p', ACL_IPROP }, - { 's', ACL_SETKEY }, - { 'x', ACL_ALL_MASK }, - { '*', ACL_ALL_MASK }, - { 'e', ACL_EXTRACT }, - { '\0', 0 } -}; - -typedef struct _wildstate { - int nwild; - const krb5_data *backref[9]; -} wildstate_t; - -static aent_t *acl_list_head = (aent_t *) NULL; -static aent_t *acl_list_tail = (aent_t *) NULL; - -static const char *acl_acl_file = (char *) NULL; -static int acl_inited = 0; -static int acl_debug_level = 0; -/* - * This is the catchall entry. If nothing else appropriate is found, or in - * the case where the ACL file is not present, this entry controls what can - * be done. - */ -static const char *acl_catchall_entry = NULL; - -static const char *acl_line2long_msg = N_("%s: line %d too long, truncated"); -static const char *acl_op_bad_msg = N_("Unrecognized ACL operation '%c' in " - "%s"); -static const char *acl_syn_err_msg = N_("%s: syntax error at line %d " - "<%10s...>"); -static const char *acl_cantopen_msg = N_("%s while opening ACL file %s"); - -/* - * kadm5int_acl_get_line() - Get a line from the ACL file. - * Lines ending with \ are continued on the next line - */ -static char * -kadm5int_acl_get_line(fp, lnp) - FILE *fp; - int *lnp; /* caller should set to 1 before first call */ -{ - int i, domore; - static int line_incr = 0; - static char acl_buf[BUFSIZ]; - - *lnp += line_incr; - line_incr = 0; - for (domore = 1; domore && !feof(fp); ) { - /* Copy in the line, with continuations */ - for (i = 0; ((i < BUFSIZ) && !feof(fp)); i++) { - int byte; - byte = fgetc(fp); - acl_buf[i] = byte; - if (byte == EOF) { - if (i > 0 && acl_buf[i-1] == '\\') - i--; - break; /* it gets nulled-out below */ - } - else if (acl_buf[i] == '\n') { - if (i == 0 || acl_buf[i-1] != '\\') - break; /* empty line or normal end of line */ - else { - i -= 2; /* back up over "\\\n" and continue */ - line_incr++; - } - } - } - /* Check if we exceeded our buffer size */ - if (i == sizeof acl_buf && (i--, !feof(fp))) { - int c1 = acl_buf[i], c2; - - krb5_klog_syslog(LOG_ERR, _(acl_line2long_msg), acl_acl_file, - *lnp); - while ((c2 = fgetc(fp)) != EOF) { - if (c2 == '\n') { - if (c1 != '\\') - break; - line_incr++; - } - c1 = c2; - } - } - acl_buf[i] = '\0'; - if (acl_buf[0] == (char) EOF) /* ptooey */ - acl_buf[0] = '\0'; - else - line_incr++; - if ((acl_buf[0] != '#') && (acl_buf[0] != '\0')) - domore = 0; - } - if (domore || (strlen(acl_buf) == 0)) - return((char *) NULL); - else - return(acl_buf); -} - -/* - * kadm5int_acl_parse_line() - Parse the contents of an ACL line. - */ -static aent_t * -kadm5int_acl_parse_line(lp) - const char *lp; -{ - static char acle_principal[BUFSIZ]; - static char acle_ops[BUFSIZ]; - static char acle_object[BUFSIZ]; - static char acle_restrictions[BUFSIZ]; - aent_t *acle; - char *op; - int t, found, opok, nmatch; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_parse_line(line=%20s)\n", lp)); - /* - * Format is still simple: - * entry ::= [<whitespace>] <principal> <whitespace> <opstring> - * [<whitespace> <target> [<whitespace> <restrictions> - * [<whitespace>]]] - */ - acle = (aent_t *) NULL; - acle_object[0] = '\0'; - nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops, - acle_object, acle_restrictions); - if (nmatch >= 2) { - acle = (aent_t *) malloc(sizeof(aent_t)); - if (acle) { - acle->ae_next = (aent_t *) NULL; - acle->ae_op_allowed = (krb5_int32) 0; - acle->ae_target = - (nmatch >= 3) ? strdup(acle_object) : (char *) NULL; - acle->ae_target_bad = 0; - acle->ae_target_princ = (krb5_principal) NULL; - opok = 1; - for (op=acle_ops; *op; op++) { - char rop; - - rop = (isupper((unsigned char) *op)) ? tolower((unsigned char) *op) : *op; - found = 0; - for (t=0; acl_op_table[t].ao_op; t++) { - if (rop == acl_op_table[t].ao_op) { - found = 1; - if (rop == *op) - acle->ae_op_allowed |= acl_op_table[t].ao_mask; - else - acle->ae_op_allowed &= ~acl_op_table[t].ao_mask; - } - } - if (!found) { - krb5_klog_syslog(LOG_ERR, _(acl_op_bad_msg), *op, lp); - opok = 0; - } - } - if (opok) { - acle->ae_name = strdup(acle_principal); - if (acle->ae_name) { - acle->ae_principal = (krb5_principal) NULL; - acle->ae_name_bad = 0; - DPRINT(DEBUG_ACL, acl_debug_level, - ("A ACL entry %s -> opmask %x\n", - acle->ae_name, acle->ae_op_allowed)); - } - else { - if (acle->ae_target) - free(acle->ae_target); - free(acle); - acle = (aent_t *) NULL; - } - } - else { - if (acle->ae_target) - free(acle->ae_target); - free(acle); - acle = (aent_t *) NULL; - } - - if (acle) { - if ( nmatch >= 4 ) { - char *trailing; - - trailing = &acle_restrictions[strlen(acle_restrictions)-1]; - while ( isspace((int) *trailing) ) - trailing--; - trailing[1] = '\0'; - acle->ae_restriction_string = - strdup(acle_restrictions); - } - else { - acle->ae_restriction_string = (char *) NULL; - } - acle->ae_restriction_bad = 0; - acle->ae_restrictions = (restriction_t *) NULL; - } - } - } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_parse_line() = %x\n", (long) acle)); - return(acle); -} - -/* - * kadm5int_acl_parse_restrictions() - Parse optional restrictions field - * - * Allowed restrictions are: - * [+-]flagname (recognized by krb5_flagspec_to_mask) - * flag is forced to indicated value - * -clearpolicy policy is forced clear - * -policy pol policy is forced to be "pol" - * -{expire,pwexpire,maxlife,maxrenewlife} deltat - * associated value will be forced to - * MIN(deltat, requested value) - * - * Returns: 0 on success, or system errors - */ -static krb5_error_code -kadm5int_acl_parse_restrictions(s, rpp) - char *s; - restriction_t **rpp; -{ - char *sp = NULL, *tp, *ap, *save; - static const char *delims = "\t\n\f\v\r ,"; - krb5_deltat dt; - krb5_error_code code; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp)); - - *rpp = (restriction_t *) NULL; - code = 0; - if (s) { - if (!(sp = strdup(s)) /* Don't munge the original */ - || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) { - code = ENOMEM; - } else { - memset(*rpp, 0, sizeof(**rpp)); - (*rpp)->forbid_attrs = ~(krb5_flags)0; - for (tp = strtok_r(sp, delims, &save); tp; - tp = strtok_r(NULL, delims, &save)) { - if (!krb5_flagspec_to_mask(tp, &(*rpp)->require_attrs, - &(*rpp)->forbid_attrs)) { - (*rpp)->mask |= KADM5_ATTRIBUTES; - } else if (!strcmp(tp, "-clearpolicy")) { - (*rpp)->mask |= KADM5_POLICY_CLR; - } else { - /* everything else needs an argument ... */ - if (!(ap = strtok_r(NULL, delims, &save))) { - code = EINVAL; - break; - } - if (!strcmp(tp, "-policy")) { - if (!((*rpp)->policy = strdup(ap))) { - code = ENOMEM; - break; - } - (*rpp)->mask |= KADM5_POLICY; - } else { - /* all other arguments must be a deltat ... */ - if (krb5_string_to_deltat(ap, &dt)) { - code = EINVAL; - break; - } - if (!strcmp(tp, "-expire")) { - (*rpp)->princ_lifetime = dt; - (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME; - } else if (!strcmp(tp, "-pwexpire")) { - (*rpp)->pw_lifetime = dt; - (*rpp)->mask |= KADM5_PW_EXPIRATION; - } else if (!strcmp(tp, "-maxlife")) { - (*rpp)->max_life = dt; - (*rpp)->mask |= KADM5_MAX_LIFE; - } else if (!strcmp(tp, "-maxrenewlife")) { - (*rpp)->max_renewable_life = dt; - (*rpp)->mask |= KADM5_MAX_RLIFE; - } else { - code = EINVAL; - break; - } - } - } - } - if (code) { - krb5_klog_syslog(LOG_ERR, _("%s: invalid restrictions: %s"), - acl_acl_file, s); - } - } - } - if (sp) - free(sp); - if (*rpp && code) { - if ((*rpp)->policy) - free((*rpp)->policy); - free(*rpp); - *rpp = (restriction_t *) NULL; - } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n", - code, (*rpp) ? (*rpp)->mask : 0)); - return code; -} - -/* - * kadm5int_acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp - * - * Returns: 0 on success; - * malloc or timeofday errors - */ -krb5_error_code -kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp) - krb5_context kcontext; - kadm5_principal_ent_rec *recp; - long *maskp; - restriction_t *rp; -{ - krb5_error_code code; - krb5_int32 now; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n", - *maskp, (long)rp)); - if (!rp) - return 0; - if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION)) - if ((code = krb5_timeofday(kcontext, &now))) - return code; - - if (rp->mask & KADM5_ATTRIBUTES) { - recp->attributes |= rp->require_attrs; - recp->attributes &= rp->forbid_attrs; - *maskp |= KADM5_ATTRIBUTES; - } - if (rp->mask & KADM5_POLICY_CLR) { - *maskp &= ~KADM5_POLICY; - *maskp |= KADM5_POLICY_CLR; - } else if (rp->mask & KADM5_POLICY) { - if (recp->policy && strcmp(recp->policy, rp->policy)) { - free(recp->policy); - recp->policy = (char *) NULL; - } - if (!recp->policy) { - recp->policy = strdup(rp->policy); /* XDR will free it */ - if (!recp->policy) - return ENOMEM; - } - *maskp |= KADM5_POLICY; - } - if (rp->mask & KADM5_PRINC_EXPIRE_TIME) { - if (!(*maskp & KADM5_PRINC_EXPIRE_TIME) - || (recp->princ_expire_time > (now + rp->princ_lifetime))) - recp->princ_expire_time = now + rp->princ_lifetime; - *maskp |= KADM5_PRINC_EXPIRE_TIME; - } - if (rp->mask & KADM5_PW_EXPIRATION) { - if (!(*maskp & KADM5_PW_EXPIRATION) - || (recp->pw_expiration > (now + rp->pw_lifetime))) - recp->pw_expiration = now + rp->pw_lifetime; - *maskp |= KADM5_PW_EXPIRATION; - } - if (rp->mask & KADM5_MAX_LIFE) { - if (!(*maskp & KADM5_MAX_LIFE) - || (recp->max_life > rp->max_life)) - recp->max_life = rp->max_life; - *maskp |= KADM5_MAX_LIFE; - } - if (rp->mask & KADM5_MAX_RLIFE) { - if (!(*maskp & KADM5_MAX_RLIFE) - || (recp->max_renewable_life > rp->max_renewable_life)) - recp->max_renewable_life = rp->max_renewable_life; - *maskp |= KADM5_MAX_RLIFE; - } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp)); - return 0; -} - -/* - * kadm5int_acl_free_entries() - Free all ACL entries. - */ -static void -kadm5int_acl_free_entries() -{ - aent_t *ap; - aent_t *np; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n")); - for (ap=acl_list_head; ap; ap = np) { - if (ap->ae_name) - free(ap->ae_name); - if (ap->ae_principal) - krb5_free_principal((krb5_context) NULL, ap->ae_principal); - if (ap->ae_target) - free(ap->ae_target); - if (ap->ae_target_princ) - krb5_free_principal((krb5_context) NULL, ap->ae_target_princ); - if (ap->ae_restriction_string) - free(ap->ae_restriction_string); - if (ap->ae_restrictions) { - if (ap->ae_restrictions->policy) - free(ap->ae_restrictions->policy); - free(ap->ae_restrictions); - } - np = ap->ae_next; - free(ap); - } - acl_list_head = acl_list_tail = (aent_t *) NULL; - acl_inited = 0; - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n")); -} - -/* - * kadm5int_acl_load_acl_file() - Open and parse the ACL file. - */ -static int -kadm5int_acl_load_acl_file() -{ - FILE *afp; - char *alinep; - aent_t **aentpp; - int alineno; - int retval = 1; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n")); - /* Open the ACL file for read */ - afp = fopen(acl_acl_file, "r"); - if (afp) { - set_cloexec_file(afp); - alineno = 1; - aentpp = &acl_list_head; - - /* Get a non-comment line */ - while ((alinep = kadm5int_acl_get_line(afp, &alineno))) { - /* Parse it */ - *aentpp = kadm5int_acl_parse_line(alinep); - /* If syntax error, then fall out */ - if (!*aentpp) { - krb5_klog_syslog(LOG_ERR, _(acl_syn_err_msg), - acl_acl_file, alineno, alinep); - retval = 0; - break; - } - acl_list_tail = *aentpp; - aentpp = &(*aentpp)->ae_next; - } - - fclose(afp); - - if (acl_catchall_entry) { - *aentpp = kadm5int_acl_parse_line(acl_catchall_entry); - if (*aentpp) { - acl_list_tail = *aentpp; - } - else { - retval = 0; - DPRINT(DEBUG_OPERATION, acl_debug_level, - ("> catchall acl entry (%s) load failed\n", - acl_catchall_entry)); - } - } - } - else { - krb5_klog_syslog(LOG_ERR, _(acl_cantopen_msg), - error_message(errno), acl_acl_file); - if (acl_catchall_entry && - (acl_list_head = kadm5int_acl_parse_line(acl_catchall_entry))) { - acl_list_tail = acl_list_head; - } - else { - retval = 0; - DPRINT(DEBUG_OPERATION, acl_debug_level, - ("> catchall acl entry (%s) load failed\n", - acl_catchall_entry)); - } - } - - if (!retval) { - kadm5int_acl_free_entries(); - } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_load_acl_file() = %d\n", retval)); - return(retval); -} - -/* - * kadm5int_acl_match_data() - See if two data entries match. - * - * Wildcarding is only supported for a whole component. - */ -static krb5_boolean -kadm5int_acl_match_data(const krb5_data *e1, const krb5_data *e2, - int targetflag, wildstate_t *ws) -{ - krb5_boolean retval; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* acl_match_entry(%s, %s)\n", e1->data, e2->data)); - retval = 0; - if (!strncmp(e1->data, "*", e1->length)) { - retval = 1; - if (ws && !targetflag) { - if (ws->nwild >= 9) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Too many wildcards in ACL entry.\n")); - } - else - ws->backref[ws->nwild++] = e2; - } - } - else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') && - (e1->data[1] >= '1') && (e1->data[1] <= '9')) { - int n = e1->data[1] - '1'; - if (n >= ws->nwild) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Too many backrefs in ACL entry.\n")); - } - else if ((ws->backref[n]->length == e2->length) && - (!strncmp(ws->backref[n]->data, e2->data, e2->length))) - retval = 1; - - } - else { - if ((e1->length == e2->length) && - (!strncmp(e1->data, e2->data, e1->length))) - retval = 1; - } - DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval)); - return(retval); -} - -/* - * kadm5int_acl_find_entry() - Find a matching entry. - */ -static aent_t * -kadm5int_acl_find_entry(krb5_context kcontext, krb5_const_principal principal, - krb5_const_principal dest_princ) -{ - aent_t *entry; - krb5_error_code kret; - int i; - int matchgood; - wildstate_t state; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n")); - for (entry=acl_list_head; entry; entry = entry->ae_next) { - memset(&state, 0, sizeof(state)); - if (entry->ae_name_bad) - continue; - if (!strcmp(entry->ae_name, "*")) { - DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n")); - matchgood = 1; - } - else { - if (!entry->ae_principal && !entry->ae_name_bad) { - kret = krb5_parse_name(kcontext, - entry->ae_name, - &entry->ae_principal); - if (kret) - entry->ae_name_bad = 1; - } - if (entry->ae_name_bad) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Bad ACL entry %s\n", entry->ae_name)); - continue; - } - matchgood = 0; - if (kadm5int_acl_match_data(&entry->ae_principal->realm, - &principal->realm, 0, (wildstate_t *)0) && - (entry->ae_principal->length == principal->length)) { - matchgood = 1; - for (i=0; i<principal->length; i++) { - if (!kadm5int_acl_match_data(&entry->ae_principal->data[i], - &principal->data[i], 0, &state)) { - matchgood = 0; - break; - } - } - } - } - if (!matchgood) - continue; - - /* We've matched the principal. If we have a target, then try it */ - if (entry->ae_target && strcmp(entry->ae_target, "*")) { - if (!entry->ae_target_princ && !entry->ae_target_bad) { - kret = krb5_parse_name(kcontext, entry->ae_target, - &entry->ae_target_princ); - if (kret) - entry->ae_target_bad = 1; - } - if (entry->ae_target_bad) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Bad target in ACL entry for %s\n", entry->ae_name)); - entry->ae_name_bad = 1; - continue; - } - if (!dest_princ) - matchgood = 0; - else if (entry->ae_target_princ && dest_princ) { - if (kadm5int_acl_match_data(&entry->ae_target_princ->realm, - &dest_princ->realm, 1, (wildstate_t *)0) && - (entry->ae_target_princ->length == dest_princ->length)) { - for (i=0; i<dest_princ->length; i++) { - if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i], - &dest_princ->data[i], 1, &state)) { - matchgood = 0; - break; - } - } - } - else - matchgood = 0; - } - } - if (!matchgood) - continue; - - if (entry->ae_restriction_string - && !entry->ae_restriction_bad - && !entry->ae_restrictions - && kadm5int_acl_parse_restrictions(entry->ae_restriction_string, - &entry->ae_restrictions)) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Bad restrictions in ACL entry for %s\n", entry->ae_name)); - entry->ae_restriction_bad = 1; - } - if (entry->ae_restriction_bad) { - entry->ae_name_bad = 1; - continue; - } - break; - } - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry)); - return(entry); -} - -/* - * kadm5int_acl_init() - Initialize ACL context. - */ -krb5_error_code -kadm5int_acl_init(kcontext, debug_level, acl_file) - krb5_context kcontext; - int debug_level; - char *acl_file; -{ - krb5_error_code kret; - - kret = 0; - acl_debug_level = debug_level; - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_init(afile=%s)\n", - ((acl_file) ? acl_file : "(null)"))); - acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL; - acl_inited = kadm5int_acl_load_acl_file(); - - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret)); - return(kret); -} - -/* - * kadm5int_acl_finish - Terminate ACL context. - */ -void -kadm5int_acl_finish(kcontext, debug_level) - krb5_context kcontext; - int debug_level; -{ - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n")); - kadm5int_acl_free_entries(); - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n")); -} - -/* - * kadm5int_acl_check_krb() - Is this operation permitted for this principal? - */ -krb5_boolean -kadm5int_acl_check_krb(kcontext, caller_princ, opmask, principal, restrictions) - krb5_context kcontext; - krb5_const_principal caller_princ; - krb5_int32 opmask; - krb5_const_principal principal; - restriction_t **restrictions; -{ - krb5_boolean retval; - aent_t *aentry; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n")); - - retval = FALSE; - - aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal); - if (aentry) { - if ((aentry->ae_op_allowed & opmask) == opmask) { - retval = TRUE; - if (restrictions) { - *restrictions = - (aentry->ae_restrictions && aentry->ae_restrictions->mask) - ? aentry->ae_restrictions - : (restriction_t *) NULL; - } - } - } - - DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n", - retval)); - return retval; -} - -/* - * kadm5int_acl_check() - Is this operation permitted for this principal? - * this code used not to be based on gssapi. In order - * to minimize porting hassles, I've put all the - * gssapi hair in this function. This might not be - * the best medium-term solution. (The best long-term - * solution is, of course, a real authorization service.) - */ -krb5_boolean -kadm5int_acl_check(kcontext, caller, opmask, principal, restrictions) - krb5_context kcontext; - gss_name_t caller; - krb5_int32 opmask; - krb5_principal principal; - restriction_t **restrictions; -{ - krb5_boolean retval; - gss_buffer_desc caller_buf; - gss_OID caller_oid; - OM_uint32 emin; - krb5_error_code code; - krb5_principal caller_princ; - - if (GSS_ERROR(gss_display_name(&emin, caller, &caller_buf, &caller_oid))) - return FALSE; - - code = krb5_parse_name(kcontext, (char *) caller_buf.value, - &caller_princ); - - gss_release_buffer(&emin, &caller_buf); - - if (code != 0) - return FALSE; - - retval = kadm5int_acl_check_krb(kcontext, caller_princ, - opmask, principal, restrictions); - - krb5_free_principal(kcontext, caller_princ); - - return retval; -} - -kadm5_ret_t -kadm5_get_privs(void *server_handle, long *privs) -{ - CHECK_HANDLE(server_handle); - - /* this is impossible to do with the current interface. For now, - return all privs, which will confuse some clients, but not - deny any access to users of "smart" clients which try to cache */ - - *privs = ~0; - - return KADM5_OK; -} diff --git a/src/lib/kadm5/srv/server_acl.h b/src/lib/kadm5/srv/server_acl.h deleted file mode 100644 index d8db2f75b087..000000000000 --- a/src/lib/kadm5/srv/server_acl.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* lib/kadm5/srv/server_acl.h */ -/* - * Copyright 1995-2004, 2007, 2008 by the Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * 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. - */ - -#ifndef SERVER_ACL_H__ -#define SERVER_ACL_H__ - -/* - * Debug definitions. - */ -#define DEBUG_SPROC 1 -#define DEBUG_OPERATION 2 -#define DEBUG_HOST 4 -#define DEBUG_REALM 8 -#define DEBUG_REQUESTS 16 -#define DEBUG_ACL 32 -#define DEBUG_PROTO 64 -#define DEBUG_CALLS 128 -#define DEBUG_NOSLAVES 256 -#ifdef DEBUG -#define DPRINT(l1, cl, al) if ((cl & l1) != 0) printf al -#else /* DEBUG */ -#define DPRINT(l1, cl, al) -#endif /* DEBUG */ - -/* - * Access control bits. - */ -#define ACL_ADD 1 -#define ACL_DELETE 2 -#define ACL_MODIFY 4 -#define ACL_CHANGEPW 8 -/* #define ACL_CHANGE_OWN_PW 16 */ -#define ACL_INQUIRE 32 -#define ACL_EXTRACT 64 -#define ACL_LIST 128 -#define ACL_SETKEY 256 -#define ACL_IPROP 512 -#define ACL_RENAME (ACL_ADD+ACL_DELETE) - -#define ACL_ALL_MASK (ACL_ADD | \ - ACL_DELETE | \ - ACL_MODIFY | \ - ACL_CHANGEPW | \ - ACL_INQUIRE | \ - ACL_LIST | \ - ACL_IPROP | \ - ACL_SETKEY) - -typedef struct _restriction { - long mask; - krb5_flags require_attrs; - krb5_flags forbid_attrs; - krb5_deltat princ_lifetime; - krb5_deltat pw_lifetime; - krb5_deltat max_life; - krb5_deltat max_renewable_life; - long aux_attributes; - char *policy; -} restriction_t; - -krb5_error_code kadm5int_acl_init(krb5_context, int, char *); -void kadm5int_acl_finish(krb5_context, int); -krb5_boolean kadm5int_acl_check(krb5_context, - gss_name_t, - krb5_int32, - krb5_principal, - restriction_t **); -krb5_boolean kadm5int_acl_check_krb(krb5_context, - krb5_const_principal, - krb5_int32, - krb5_const_principal, - restriction_t **); -krb5_error_code kadm5int_acl_impose_restrictions(krb5_context, - kadm5_principal_ent_rec *, - long *, - restriction_t *); -#endif /* SERVER_ACL_H__ */ diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c index 612553ba3e19..f4b8aef2bde1 100644 --- a/src/lib/kadm5/srv/server_kdb.c +++ b/src/lib/kadm5/srv/server_kdb.c @@ -365,7 +365,7 @@ kdb_put_entry(kadm5_server_handle_t handle, krb5_db_entry *kdb, osa_princ_ent_rec *adb) { krb5_error_code ret; - krb5_int32 now; + krb5_timestamp now; XDR xdrs; krb5_tl_data tl_data; diff --git a/src/lib/kadm5/srv/server_misc.c b/src/lib/kadm5/srv/server_misc.c index b361847bd553..87e97c9f8a2f 100644 --- a/src/lib/kadm5/srv/server_misc.c +++ b/src/lib/kadm5/srv/server_misc.c @@ -142,3 +142,17 @@ destroy_pwqual(kadm5_server_handle_t handle) k5_pwqual_free_handles(handle->context, handle->qual_handles); handle->qual_handles = NULL; } + +kadm5_ret_t +kadm5_get_privs(void *server_handle, long *privs) +{ + CHECK_HANDLE(server_handle); + + /* this is impossible to do with the current interface. For now, + return all privs, which will confuse some clients, but not + deny any access to users of "smart" clients which try to cache */ + + *privs = ~0; + + return KADM5_OK; +} diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index 0640b47c40d4..2420f2c2bebb 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -296,7 +296,7 @@ kadm5_create_principal_3(void *server_handle, osa_princ_ent_rec adb; kadm5_policy_ent_rec polent; krb5_boolean have_polent = FALSE; - krb5_int32 now; + krb5_timestamp now; krb5_tl_data *tl_data_tail; unsigned int ret; kadm5_server_handle_t handle = server_handle; @@ -400,7 +400,7 @@ kadm5_create_principal_3(void *server_handle, kdb->pw_expiration = 0; if (have_polent) { if(polent.pw_max_life) - kdb->pw_expiration = now + polent.pw_max_life; + kdb->pw_expiration = ts_incr(now, polent.pw_max_life); else kdb->pw_expiration = 0; } @@ -612,7 +612,7 @@ kadm5_modify_principal(void *server_handle, &(kdb->pw_expiration)); if (ret) goto done; - kdb->pw_expiration += pol.pw_max_life; + kdb->pw_expiration = ts_incr(kdb->pw_expiration, pol.pw_max_life); } else { kdb->pw_expiration = 0; } @@ -1322,11 +1322,11 @@ kadm5_chpass_principal_3(void *server_handle, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password) { - krb5_int32 now; + krb5_timestamp now; kadm5_policy_ent_rec pol; osa_princ_ent_rec adb; krb5_db_entry *kdb; - int ret, ret2, last_pwd, hist_added; + int ret, ret2, hist_added; krb5_boolean have_pol = FALSE; kadm5_server_handle_t handle = server_handle; osa_pw_hist_ent hist; @@ -1399,24 +1399,6 @@ kadm5_chpass_principal_3(void *server_handle, if ((adb.aux_attributes & KADM5_POLICY)) { /* the policy was loaded before */ - ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd); - if (ret) - goto done; - -#if 0 - /* - * The spec says this check is overridden if the caller has - * modify privilege. The admin server therefore makes this - * check itself (in chpass_principal_wrapper, misc.c). A - * local caller implicitly has all authorization bits. - */ - if ((now - last_pwd) < pol.pw_min_life && - !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { - ret = KADM5_PASS_TOOSOON; - goto done; - } -#endif - ret = check_pw_reuse(handle->context, hist_keyblocks, kdb->n_key_data, kdb->key_data, 1, &hist); @@ -1445,7 +1427,7 @@ kadm5_chpass_principal_3(void *server_handle, } if (pol.pw_max_life) - kdb->pw_expiration = now + pol.pw_max_life; + kdb->pw_expiration = ts_incr(now, pol.pw_max_life); else kdb->pw_expiration = 0; } else { @@ -1544,9 +1526,9 @@ kadm5_randkey_principal_3(void *server_handle, { krb5_db_entry *kdb; osa_princ_ent_rec adb; - krb5_int32 now; + krb5_timestamp now; kadm5_policy_ent_rec pol; - int ret, last_pwd, n_new_keys; + int ret, n_new_keys; krb5_boolean have_pol = FALSE; kadm5_server_handle_t handle = server_handle; krb5_keyblock *act_mkey; @@ -1605,26 +1587,8 @@ kadm5_randkey_principal_3(void *server_handle, goto done; } if (have_pol) { - ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd); - if (ret) - goto done; - -#if 0 - /* - * The spec says this check is overridden if the caller has - * modify privilege. The admin server therefore makes this - * check itself (in chpass_principal_wrapper, misc.c). A - * local caller implicitly has all authorization bits. - */ - if((now - last_pwd) < pol.pw_min_life && - !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { - ret = KADM5_PASS_TOOSOON; - goto done; - } -#endif - if (pol.pw_max_life) - kdb->pw_expiration = now + pol.pw_max_life; + kdb->pw_expiration = ts_incr(now, pol.pw_max_life); else kdb->pw_expiration = 0; } else { @@ -1686,14 +1650,11 @@ kadm5_setv4key_principal(void *server_handle, { krb5_db_entry *kdb; osa_princ_ent_rec adb; - krb5_int32 now; + krb5_timestamp now; kadm5_policy_ent_rec pol; krb5_keysalt keysalt; int i, kvno, ret; krb5_boolean have_pol = FALSE; -#if 0 - int last_pwd; -#endif kadm5_server_handle_t handle = server_handle; krb5_key_data tmp_key_data; krb5_keyblock *act_mkey; @@ -1756,25 +1717,8 @@ kadm5_setv4key_principal(void *server_handle, goto done; } if (have_pol) { -#if 0 - /* - * The spec says this check is overridden if the caller has - * modify privilege. The admin server therefore makes this - * check itself (in chpass_principal_wrapper, misc.c). A - * local caller implicitly has all authorization bits. - */ - if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, - kdb, &last_pwd)) - goto done; - if((now - last_pwd) < pol.pw_min_life && - !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { - ret = KADM5_PASS_TOOSOON; - goto done; - } -#endif - if (pol.pw_max_life) - kdb->pw_expiration = now + pol.pw_max_life; + kdb->pw_expiration = ts_incr(now, pol.pw_max_life); else kdb->pw_expiration = 0; } else { @@ -1788,6 +1732,9 @@ kadm5_setv4key_principal(void *server_handle, /* unlock principal on this KDC */ kdb->fail_auth_count = 0; + /* key data changed, let the database provider know */ + kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT; + if ((ret = kdb_put_entry(handle, kdb, &adb))) goto done; @@ -1888,7 +1835,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal, { krb5_db_entry *kdb; osa_princ_ent_rec adb; - krb5_int32 now; + krb5_timestamp now; kadm5_policy_ent_rec pol; krb5_key_data *new_key_data = NULL; int i, j, ret, n_new_key_data = 0; @@ -2024,7 +1971,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal, } if (have_pol) { if (pol.pw_max_life) - kdb->pw_expiration = now + pol.pw_max_life; + kdb->pw_expiration = ts_incr(now, pol.pw_max_life); else kdb->pw_expiration = 0; } else { @@ -2038,6 +1985,9 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal, /* Unlock principal on this KDC. */ kdb->fail_auth_count = 0; + /* key data changed, let the database provider know */ + kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT; + ret = kdb_put_entry(handle, kdb, &adb); if (ret) goto done; diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/unit-test/setkey-test.c index 60be9e85d5d3..0431653bff44 100644 --- a/src/lib/kadm5/unit-test/setkey-test.c +++ b/src/lib/kadm5/unit-test/setkey-test.c @@ -69,7 +69,8 @@ main(int argc, char **argv) char *whoami, *principal, *authprinc, *authpwd; krb5_data pwdata; void *handle; - int ret, i, test, encnum; + int ret, test, encnum; + unsigned int i; whoami = argv[0]; diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index 5da22dfd51c1..b77bf496d6a2 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -5,7 +5,7 @@ LOCALINCLUDES= -I. # Keep LIBMAJOR in sync with KRB5_KDB_API_VERSION in include/kdb.h. LIBBASE=kdb5 -LIBMAJOR=8 +LIBMAJOR=9 LIBMINOR=0 LIBINITFUNC=kdb_init_lock_list LIBFINIFUNC=kdb_fini_lock_list diff --git a/src/lib/kdb/deps b/src/lib/kdb/deps index c2ce27ff7cd8..152ef7fceee2 100644 --- a/src/lib/kdb/deps +++ b/src/lib/kdb/deps @@ -153,5 +153,6 @@ t_ulog.so t_ulog.po $(OUTPRE)t_ulog.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h t_ulog.c t_sort_key_data.so t_sort_key_data.po $(OUTPRE)t_sort_key_data.$(OBJEXT): \ - $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/kdb.h \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-cmocka.h $(top_srcdir)/include/kdb.h \ $(top_srcdir)/include/krb5.h t_sort_key_data.c diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index 4adf0fcbb201..da5332217fef 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -322,12 +322,7 @@ copy_vtable(const kdb_vftabl *in, kdb_vftabl *out) out->audit_as_req = in->audit_as_req; out->refresh_config = in->refresh_config; out->check_allowed_to_delegate = in->check_allowed_to_delegate; - - /* Copy fields for minor version 1 (major version 6). */ - assert(KRB5_KDB_DAL_MAJOR_VERSION == 6); - out->free_principal_e_data = NULL; - if (in->min_ver >= 1) - out->free_principal_e_data = in->free_principal_e_data; + out->free_principal_e_data = in->free_principal_e_data; /* Set defaults for optional fields. */ if (out->fetch_master_key == NULL) @@ -1220,11 +1215,12 @@ krb5_db_fetch_mkey(krb5_context context, krb5_principal mname, krb5_db_entry *master_entry; rc = krb5_db_get_principal(context, mname, 0, &master_entry); - if (rc == 0) { + if (rc == 0 && master_entry->n_key_data > 0) *kvno = (krb5_kvno) master_entry->key_data->key_data_kvno; - krb5_db_free_principal(context, master_entry); - } else + else *kvno = 1; + if (rc == 0) + krb5_db_free_principal(context, master_entry); } if (!salt) @@ -1296,7 +1292,7 @@ find_actkvno(krb5_actkvno_node *list, krb5_timestamp now) * are in the future, we will return the first node; if all are in the * past, we will return the last node. */ - while (list->next != NULL && list->next->act_time <= now) + while (list->next != NULL && !ts_after(list->next->act_time, now)) list = list->next; return list->act_kvno; } @@ -2677,8 +2673,10 @@ krb5_db_check_policy_tgs(krb5_context kcontext, krb5_kdc_req *request, void krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request, - krb5_db_entry *client, krb5_db_entry *server, - krb5_timestamp authtime, krb5_error_code error_code) + const krb5_address *local_addr, + const krb5_address *remote_addr, krb5_db_entry *client, + krb5_db_entry *server, krb5_timestamp authtime, + krb5_error_code error_code) { krb5_error_code status; kdb_vftabl *v; @@ -2686,7 +2684,8 @@ krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request, status = get_vftabl(kcontext, &v); if (status || v->audit_as_req == NULL) return; - v->audit_as_req(kcontext, request, client, server, authtime, error_code); + v->audit_as_req(kcontext, request, local_addr, remote_addr, + client, server, authtime, error_code); } void diff --git a/src/lib/kdb/kdb_convert.c b/src/lib/kdb/kdb_convert.c index 8172e9d6ba16..691635ec752b 100644 --- a/src/lib/kdb/kdb_convert.c +++ b/src/lib/kdb/kdb_convert.c @@ -228,7 +228,7 @@ conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd, static void set_from_utf8str(krb5_data *d, utf8str_t u) { - if (u.utf8str_t_len > INT_MAX-1 || u.utf8str_t_len >= SIZE_MAX-1) { + if (u.utf8str_t_len > INT_MAX - 1) { d->data = NULL; return; } @@ -419,7 +419,7 @@ ulog_conv_2logentry(krb5_context context, krb5_db_entry *entry, break; case AT_FAIL_AUTH_COUNT: - if (!exclude_nra && entry->fail_auth_count >= (krb5_kvno)0) { + if (!exclude_nra) { ULOG_ENTRY_TYPE(update, ++final).av_type = AT_FAIL_AUTH_COUNT; ULOG_ENTRY(update, final).av_fail_auth_count = diff --git a/src/lib/kdb/kdb_default.c b/src/lib/kdb/kdb_default.c index 7a751487ce27..a1021f13a493 100644 --- a/src/lib/kdb/kdb_default.c +++ b/src/lib/kdb/kdb_default.c @@ -282,7 +282,7 @@ krb5_db_def_fetch_mkey_stash(krb5_context context, key->length = keylength; #endif - if (!key->length || ((int) key->length) < 0) { + if (!key->length || key->length > 1024) { retval = KRB5_KDB_BADSTORED_MKEY; goto errout; } diff --git a/src/lib/kdb/t_sort_key_data.c b/src/lib/kdb/t_sort_key_data.c index d03d507a1c33..ffd1a156ac3d 100644 --- a/src/lib/kdb/t_sort_key_data.c +++ b/src/lib/kdb/t_sort_key_data.c @@ -30,10 +30,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> +#include "k5-cmocka.h" #include "kdb.h" #define KEY(kvno) { \ diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index a827ca6083e8..889460989f70 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -158,8 +158,7 @@ static asn1_error_code encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag, size_t *len_out) { - /* Range checking for time_t vs krb5_timestamp? */ - time_t val = *(krb5_timestamp *)p; + time_t val = ts2tt(*(krb5_timestamp *)p); rettag->asn1class = UNIVERSAL; rettag->construction = PRIMITIVE; rettag->tagnum = ASN1_GENERALTIME; diff --git a/src/lib/krb5/ccache/Makefile.in b/src/lib/krb5/ccache/Makefile.in index 5ac870728d9d..f84cf793e0db 100644 --- a/src/lib/krb5/ccache/Makefile.in +++ b/src/lib/krb5/ccache/Makefile.in @@ -34,6 +34,7 @@ STLIBOBJS= \ ccdefops.o \ ccmarshal.o \ ccselect.o \ + ccselect_hostname.o \ ccselect_k5identity.o \ ccselect_realm.o \ cc_dir.o \ @@ -52,6 +53,7 @@ OBJS= $(OUTPRE)ccbase.$(OBJEXT) \ $(OUTPRE)ccdefops.$(OBJEXT) \ $(OUTPRE)ccmarshal.$(OBJEXT) \ $(OUTPRE)ccselect.$(OBJEXT) \ + $(OUTPRE)ccselect_hostname.$(OBJEXT) \ $(OUTPRE)ccselect_k5identity.$(OBJEXT) \ $(OUTPRE)ccselect_realm.$(OBJEXT) \ $(OUTPRE)cc_dir.$(OBJEXT) \ @@ -70,6 +72,7 @@ SRCS= $(srcdir)/ccbase.c \ $(srcdir)/ccdefops.c \ $(srcdir)/ccmarshal.c \ $(srcdir)/ccselect.c \ + $(srcdir)/ccselect_hostname.c \ $(srcdir)/ccselect_k5identity.c \ $(srcdir)/ccselect_realm.c \ $(srcdir)/cc_dir.c \ diff --git a/src/lib/krb5/ccache/cc-int.h b/src/lib/krb5/ccache/cc-int.h index ee9b5e0e97a1..d920367cea97 100644 --- a/src/lib/krb5/ccache/cc-int.h +++ b/src/lib/krb5/ccache/cc-int.h @@ -124,6 +124,10 @@ krb5_error_code krb5int_fcc_new_unique(krb5_context context, char *template, krb5_ccache *id); krb5_error_code +ccselect_hostname_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +krb5_error_code ccselect_realm_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c index a889e67b4492..b621ed33b3e7 100644 --- a/src/lib/krb5/ccache/cc_kcm.c +++ b/src/lib/krb5/ccache/cc_kcm.c @@ -32,7 +32,7 @@ /* * This cache type contacts a daemon for each cache operation, using Heimdal's - * KCM protocol. On OS X, the preferred transport is Mach RPC; on other + * KCM protocol. On macOS, the preferred transport is Mach RPC; on other * Unix-like platforms or if the daemon is not available via RPC, Unix domain * sockets are used instead. */ @@ -360,7 +360,7 @@ kcmio_connect(krb5_context context, struct kcmio **io_out) return ENOMEM; io->fd = -1; - /* Try Mach RPC (OS X only), then fall back to Unix domain sockets */ + /* Try Mach RPC (macOS only), then fall back to Unix domain sockets */ ret = kcmio_mach_connect(context, io); if (ret) ret = kcmio_unix_socket_connect(context, io); diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c index 4fe3f0d6f1f2..fba710b1b651 100644 --- a/src/lib/krb5/ccache/cc_keyring.c +++ b/src/lib/krb5/ccache/cc_keyring.c @@ -751,7 +751,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) for (;;) { if (krcc_next_cred(context, id, &cursor, &creds) != 0) break; - if (creds.times.endtime > endtime) + if (ts_after(creds.times.endtime, endtime)) endtime = creds.times.endtime; krb5_free_cred_contents(context, &creds); } @@ -765,7 +765,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) /* Setting the timeout to zero would reset the timeout, so we set it to one * second instead if creds are already expired. */ - timeout = (endtime > now) ? endtime - now : 1; + timeout = ts_after(endtime, now) ? ts_delta(endtime, now) : 1; (void)keyctl_set_timeout(data->cache_id, timeout); } @@ -1316,8 +1316,10 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds) if (ret) goto errout; - if (creds->times.endtime > now) - (void)keyctl_set_timeout(cred_key, creds->times.endtime - now); + if (ts_after(creds->times.endtime, now)) { + (void)keyctl_set_timeout(cred_key, + ts_delta(creds->times.endtime, now)); + } update_keyring_expiration(context, id); @@ -1680,8 +1682,8 @@ static void krcc_update_change_time(krcc_data *data) { krb5_timestamp now_time = time(NULL); - data->changetime = (data->changetime >= now_time) ? - data->changetime + 1 : now_time; + data->changetime = ts_after(now_time, data->changetime) ? + now_time : ts_incr(data->changetime, 1); } /* diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c index 0354575c5c16..c5425eb3ae7a 100644 --- a/src/lib/krb5/ccache/cc_memory.c +++ b/src/lib/krb5/ccache/cc_memory.c @@ -720,8 +720,8 @@ static void update_mcc_change_time(krb5_mcc_data *d) { krb5_timestamp now_time = time(NULL); - d->changetime = (d->changetime >= now_time) ? - d->changetime + 1 : now_time; + d->changetime = ts_after(now_time, d->changetime) ? + now_time : ts_incr(d->changetime, 1); } static krb5_error_code KRB5_CALLCONV diff --git a/src/lib/krb5/ccache/cc_mslsa.c b/src/lib/krb5/ccache/cc_mslsa.c index 7a8047023716..c741a5099ae6 100644 --- a/src/lib/krb5/ccache/cc_mslsa.c +++ b/src/lib/krb5/ccache/cc_mslsa.c @@ -1553,6 +1553,7 @@ krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual) data->LogonHandle = LogonHandle; data->PackageId = PackageId; data->princ = NULL; + data->flags = 0; data->cc_name = (char *)malloc(strlen(residual)+1); if (data->cc_name == NULL) { diff --git a/src/lib/krb5/ccache/cc_retr.c b/src/lib/krb5/ccache/cc_retr.c index 1314d24bd68d..e8a20fe36001 100644 --- a/src/lib/krb5/ccache/cc_retr.c +++ b/src/lib/krb5/ccache/cc_retr.c @@ -46,11 +46,11 @@ static krb5_boolean times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2) { if (t1->renew_till) { - if (t1->renew_till > t2->renew_till) + if (ts_after(t1->renew_till, t2->renew_till)) return FALSE; /* this one expires too late */ } if (t1->endtime) { - if (t1->endtime > t2->endtime) + if (ts_after(t1->endtime, t2->endtime)) return FALSE; /* this one expires too late */ } /* only care about expiration on a times_match */ @@ -211,7 +211,6 @@ krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id, int pref; } fetched, best; int have_creds = 0; - krb5_flags oflags = 0; #define fetchcreds (fetched.creds) kret = krb5_cc_start_seq_get(context, id, &cursor); diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c index 9f44af3d087c..6092ee432222 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc_util.c +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c @@ -16,8 +16,8 @@ #include <malloc.h> #endif +#include "k5-int.h" #include "stdcc_util.h" -#include "krb5.h" #ifdef _WIN32 /* it's part of krb5.h everywhere else */ #include "kv5m_err.h" #endif @@ -321,10 +321,10 @@ copy_cc_cred_union_to_krb5_creds (krb5_context in_context, keyblock_contents = NULL; /* copy times */ - out_creds->times.authtime = cv5->authtime + offset_seconds; - out_creds->times.starttime = cv5->starttime + offset_seconds; - out_creds->times.endtime = cv5->endtime + offset_seconds; - out_creds->times.renew_till = cv5->renew_till + offset_seconds; + out_creds->times.authtime = ts_incr(cv5->authtime, offset_seconds); + out_creds->times.starttime = ts_incr(cv5->starttime, offset_seconds); + out_creds->times.endtime = ts_incr(cv5->endtime, offset_seconds); + out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds); out_creds->is_skey = cv5->is_skey; out_creds->ticket_flags = cv5->ticket_flags; @@ -451,11 +451,11 @@ copy_krb5_creds_to_cc_cred_union (krb5_context in_context, cv5->keyblock.data = keyblock_data; keyblock_data = NULL; - cv5->authtime = in_creds->times.authtime - offset_seconds; - cv5->starttime = in_creds->times.starttime - offset_seconds; - cv5->endtime = in_creds->times.endtime - offset_seconds; - cv5->renew_till = in_creds->times.renew_till - offset_seconds; - cv5->is_skey = in_creds->is_skey; + cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds); + cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds); + cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds); + cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds); + cv5->is_skey = in_creds->is_skey; cv5->ticket_flags = in_creds->ticket_flags; if (in_creds->ticket.data) { @@ -732,10 +732,10 @@ void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif - dest->times.authtime = src->authtime + offset_seconds; - dest->times.starttime = src->starttime + offset_seconds; - dest->times.endtime = src->endtime + offset_seconds; - dest->times.renew_till = src->renew_till + offset_seconds; + dest->times.authtime = ts_incr(src->authtime, offset_seconds); + dest->times.starttime = ts_incr(src->starttime, offset_seconds); + dest->times.endtime = ts_incr(src->endtime, offset_seconds); + dest->times.renew_till = ts_incr(src->renew_till, offset_seconds); dest->is_skey = src->is_skey; dest->ticket_flags = src->ticket_flags; @@ -804,10 +804,10 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif - c->authtime = creds->times.authtime - offset_seconds; - c->starttime = creds->times.starttime - offset_seconds; - c->endtime = creds->times.endtime - offset_seconds; - c->renew_till = creds->times.renew_till - offset_seconds; + c->authtime = ts_incr(creds->times.authtime, -offset_seconds); + c->starttime = ts_incr(creds->times.starttime, -offset_seconds); + c->endtime = ts_incr(creds->times.endtime, -offset_seconds); + c->renew_till = ts_incr(creds->times.renew_till, -offset_seconds); c->is_skey = creds->is_skey; c->ticket_flags = creds->ticket_flags; @@ -925,11 +925,11 @@ times_match(t1, t2) register const krb5_ticket_times *t2; { if (t1->renew_till) { - if (t1->renew_till > t2->renew_till) + if (ts_after(t1->renew_till, t2->renew_till)) return FALSE; /* this one expires too late */ } if (t1->endtime) { - if (t1->endtime > t2->endtime) + if (ts_after(t1->endtime, t2->endtime)) return FALSE; /* this one expires too late */ } /* only care about expiration on a times_match */ diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c index c31a3f5f0b87..506a27c1b969 100644 --- a/src/lib/krb5/ccache/cccursor.c +++ b/src/lib/krb5/ccache/cccursor.c @@ -159,7 +159,7 @@ krb5_cccol_last_change_time(krb5_context context, ret = krb5_cccol_cursor_next(context, c, &ccache); if (ccache) { ret = krb5_cc_last_change_time(context, ccache, &last_time); - if (!ret && last_time > max_change_time) { + if (!ret && ts_after(last_time, max_change_time)) { max_change_time = last_time; } ret = 0; @@ -230,14 +230,37 @@ save_first_error(krb5_context context, krb5_error_code code, k5_save_ctx_error(context, code, errsave); } +/* Return 0 if cache contains any non-config credentials. Return KRB5_CC_END + * if it does not, or another error if we failed to read through it. */ +static krb5_error_code +has_content(krb5_context context, krb5_ccache cache) +{ + krb5_error_code ret; + krb5_boolean found = FALSE; + krb5_cc_cursor cache_cursor; + krb5_creds creds; + + ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); + if (ret) + return ret; + while (!found) { + ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); + if (ret) + break; + if (!krb5_is_config_principal(context, creds.server)) + found = TRUE; + krb5_free_cred_contents(context, &creds); + } + krb5_cc_end_seq_get(context, cache, &cache_cursor); + return ret; +} + krb5_error_code KRB5_CALLCONV krb5_cccol_have_content(krb5_context context) { krb5_error_code ret; krb5_cccol_cursor col_cursor; - krb5_cc_cursor cache_cursor; krb5_ccache cache; - krb5_creds creds; krb5_boolean found = FALSE; struct errinfo errsave = EMPTY_ERRINFO; const char *defname; @@ -252,24 +275,10 @@ krb5_cccol_have_content(krb5_context context) save_first_error(context, ret, &errsave); if (ret || cache == NULL) break; - - ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); + ret = has_content(context, cache); save_first_error(context, ret, &errsave); - if (ret) { - krb5_cc_close(context, cache); - continue; - } - while (!found) { - ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); - save_first_error(context, ret, &errsave); - if (ret) - break; - - if (!krb5_is_config_principal(context, creds.server)) - found = TRUE; - krb5_free_cred_contents(context, &creds); - } - krb5_cc_end_seq_get(context, cache, &cache_cursor); + if (!ret) + found = TRUE; krb5_cc_close(context, cache); } krb5_cccol_cursor_free(context, &col_cursor); diff --git a/src/lib/krb5/ccache/ccmarshal.c b/src/lib/krb5/ccache/ccmarshal.c index bd6d309d1d4e..ae634ccab0d2 100644 --- a/src/lib/krb5/ccache/ccmarshal.c +++ b/src/lib/krb5/ccache/ccmarshal.c @@ -100,8 +100,8 @@ * second value when reading it. */ -#include "k5-input.h" #include "cc-int.h" +#include "k5-input.h" /* Read a 16-bit integer in host byte order for versions 1 and 2, or in * big-endian byte order for later versions.*/ diff --git a/src/lib/krb5/ccache/ccselect.c b/src/lib/krb5/ccache/ccselect.c index 2f3071a272a2..6c360e1002ec 100644 --- a/src/lib/krb5/ccache/ccselect.c +++ b/src/lib/krb5/ccache/ccselect.c @@ -71,6 +71,11 @@ load_modules(krb5_context context) if (ret != 0) goto cleanup; + ret = k5_plugin_register(context, PLUGIN_INTERFACE_CCSELECT, "hostname", + ccselect_hostname_initvt); + if (ret != 0) + goto cleanup; + ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CCSELECT, &modules); if (ret != 0) goto cleanup; @@ -115,14 +120,6 @@ cleanup: return ret; } -static krb5_error_code -choose(krb5_context context, struct ccselect_module_handle *h, - krb5_principal server, krb5_ccache *cache_out, - krb5_principal *princ_out) -{ - return h->vt.choose(context, h->data, server, cache_out, princ_out); -} - krb5_error_code KRB5_CALLCONV krb5_cc_select(krb5_context context, krb5_principal server, krb5_ccache *cache_out, krb5_principal *princ_out) @@ -132,6 +129,8 @@ krb5_cc_select(krb5_context context, krb5_principal server, struct ccselect_module_handle **hp, *h; krb5_ccache cache; krb5_principal princ; + krb5_principal srvcp = NULL; + char **fbrealms = NULL; *cache_out = NULL; *princ_out = NULL; @@ -139,7 +138,27 @@ krb5_cc_select(krb5_context context, krb5_principal server, if (context->ccselect_handles == NULL) { ret = load_modules(context); if (ret) - return ret; + goto cleanup; + } + + /* Try to use the fallback host realm for the server if there is no + * authoritative realm. */ + if (krb5_is_referral_realm(&server->realm) && + server->type == KRB5_NT_SRV_HST && server->length == 2) { + ret = krb5_get_fallback_host_realm(context, &server->data[1], + &fbrealms); + if (ret) + goto cleanup; + + /* Make a copy with the first fallback realm. */ + ret = krb5_copy_principal(context, server, &srvcp); + if (ret) + goto cleanup; + ret = krb5_set_principal_realm(context, srvcp, fbrealms[0]); + if (ret) + goto cleanup; + + server = srvcp; } /* Consult authoritative modules first, then heuristic ones. */ @@ -149,26 +168,31 @@ krb5_cc_select(krb5_context context, krb5_principal server, h = *hp; if (h->priority != priority) continue; - ret = choose(context, h, server, &cache, &princ); + ret = h->vt.choose(context, h->data, server, &cache, &princ); if (ret == 0) { TRACE_CCSELECT_MODCHOICE(context, h->vt.name, server, cache, princ); *cache_out = cache; *princ_out = princ; - return 0; + goto cleanup; } else if (ret == KRB5_CC_NOTFOUND) { TRACE_CCSELECT_MODNOTFOUND(context, h->vt.name, server, princ); *princ_out = princ; - return ret; + goto cleanup; } else if (ret != KRB5_PLUGIN_NO_HANDLE) { TRACE_CCSELECT_MODFAIL(context, h->vt.name, ret, server); - return ret; + goto cleanup; } } } TRACE_CCSELECT_NOTFOUND(context, server); - return KRB5_CC_NOTFOUND; + ret = KRB5_CC_NOTFOUND; + +cleanup: + krb5_free_principal(context, srvcp); + krb5_free_host_realm(context, fbrealms); + return ret; } void diff --git a/src/lib/krb5/ccache/ccselect_hostname.c b/src/lib/krb5/ccache/ccselect_hostname.c new file mode 100644 index 000000000000..475cfabaefd7 --- /dev/null +++ b/src/lib/krb5/ccache/ccselect_hostname.c @@ -0,0 +1,146 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/ccache/ccselect_hostname.c - hostname ccselect module */ +/* + * Copyright (C) 2017 by Red Hat, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "cc-int.h" +#include <ctype.h> +#include <krb5/ccselect_plugin.h> + +/* Swap a and b, using tmp as an intermediate. */ +#define SWAP(a, b, tmp) \ + tmp = a; \ + a = b; \ + b = tmp; + +static krb5_error_code +hostname_init(krb5_context context, krb5_ccselect_moddata *data_out, + int *priority_out) +{ + *data_out = NULL; + *priority_out = KRB5_CCSELECT_PRIORITY_HEURISTIC; + return 0; +} + +static krb5_error_code +hostname_choose(krb5_context context, krb5_ccselect_moddata data, + krb5_principal server, krb5_ccache *ccache_out, + krb5_principal *princ_out) +{ + krb5_error_code ret; + char *p, *host = NULL; + size_t hostlen; + krb5_cccol_cursor col_cursor; + krb5_ccache ccache, tmp_ccache, best_ccache = NULL; + krb5_principal princ, tmp_princ, best_princ = NULL; + krb5_data domain; + + *ccache_out = NULL; + *princ_out = NULL; + + if (server->type != KRB5_NT_SRV_HST || server->length < 2) + return KRB5_PLUGIN_NO_HANDLE; + + /* Compute upper-case hostname. */ + hostlen = server->data[1].length; + host = k5memdup0(server->data[1].data, hostlen, &ret); + if (host == NULL) + return ret; + for (p = host; *p != '\0'; p++) { + if (islower(*p)) + *p = toupper(*p); + } + + /* Scan the collection for a cache with a client principal whose realm is + * the longest tail of the server hostname. */ + ret = krb5_cccol_cursor_new(context, &col_cursor); + if (ret) + goto done; + + for (ret = krb5_cccol_cursor_next(context, col_cursor, &ccache); + ret == 0 && ccache != NULL; + ret = krb5_cccol_cursor_next(context, col_cursor, &ccache)) { + ret = krb5_cc_get_principal(context, ccache, &princ); + if (ret) { + krb5_cc_close(context, ccache); + break; + } + + /* Check for a longer match than we have. */ + domain = make_data(host, hostlen); + while (best_princ == NULL || + best_princ->realm.length < domain.length) { + if (data_eq(princ->realm, domain)) { + SWAP(best_ccache, ccache, tmp_ccache); + SWAP(best_princ, princ, tmp_princ); + break; + } + + /* Try the next parent domain. */ + p = memchr(domain.data, '.', domain.length); + if (p == NULL) + break; + domain = make_data(p + 1, hostlen - (p + 1 - host)); + } + + if (ccache != NULL) + krb5_cc_close(context, ccache); + krb5_free_principal(context, princ); + } + + krb5_cccol_cursor_free(context, &col_cursor); + + if (best_ccache != NULL) { + *ccache_out = best_ccache; + *princ_out = best_princ; + } else { + ret = KRB5_PLUGIN_NO_HANDLE; + } + +done: + free(host); + return ret; +} + +krb5_error_code +ccselect_hostname_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_ccselect_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_ccselect_vtable)vtable; + vt->name = "hostname"; + vt->init = hostname_init; + vt->choose = hostname_choose; + return 0; +} diff --git a/src/lib/krb5/ccache/deps b/src/lib/krb5/ccache/deps index 9cd2e00d456c..6732f75548ce 100644 --- a/src/lib/krb5/ccache/deps +++ b/src/lib/krb5/ccache/deps @@ -78,6 +78,17 @@ ccselect.so ccselect.po $(OUTPRE)ccselect.$(OBJEXT): \ $(top_srcdir)/include/krb5/ccselect_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ cc-int.h ccselect.c +ccselect_hostname.so ccselect_hostname.po $(OUTPRE)ccselect_hostname.$(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 $(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/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/ccselect_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h cc-int.h ccselect_hostname.c ccselect_k5identity.so ccselect_k5identity.po $(OUTPRE)ccselect_k5identity.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c index 6a42f267df7d..091f2c43fa3a 100644 --- a/src/lib/krb5/keytab/kt_file.c +++ b/src/lib/krb5/keytab/kt_file.c @@ -264,9 +264,11 @@ more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2) * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage). */ - if (k1->timestamp >= k2->timestamp && k1->vno < 128 && k2->vno > 240) + if (!ts_after(k2->timestamp, k1->timestamp) && + k1->vno < 128 && k2->vno > 240) return TRUE; - if (k1->timestamp <= k2->timestamp && k1->vno > 240 && k2->vno < 128) + if (!ts_after(k1->timestamp, k2->timestamp) && + k1->vno > 240 && k2->vno < 128) return FALSE; /* Otherwise do a simple version comparison. */ @@ -357,7 +359,7 @@ krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, } - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || new_entry.vno == IGNORE_VNO) { /* If this entry is more recent (or the first match), free the * current and keep the new. Otherwise, free the new. */ if (cur_entry.principal == NULL || diff --git a/src/lib/krb5/keytab/kt_memory.c b/src/lib/krb5/keytab/kt_memory.c index e89fdcb4dc99..8824adf50826 100644 --- a/src/lib/krb5/keytab/kt_memory.c +++ b/src/lib/krb5/keytab/kt_memory.c @@ -403,7 +403,7 @@ krb5_mkt_get_entry(krb5_context context, krb5_keytab id, continue; } - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || entry->vno == IGNORE_VNO) { if (match == NULL) match = entry; else if (entry->vno > match->vno) diff --git a/src/lib/krb5/keytab/kt_srvtab.c b/src/lib/krb5/keytab/kt_srvtab.c index caa0158ecc2b..bbfaadfc298c 100644 --- a/src/lib/krb5/keytab/kt_srvtab.c +++ b/src/lib/krb5/keytab/kt_srvtab.c @@ -205,7 +205,7 @@ krb5_ktsrvtab_get_entry(krb5_context context, krb5_keytab id, krb5_const_princip while ((kerror = krb5_ktsrvint_read_entry(context, id, &ent)) == 0) { ent.key.enctype = enctype; if (krb5_principal_compare(context, principal, ent.principal)) { - if (kvno == IGNORE_VNO) { + if (kvno == IGNORE_VNO || ent.vno == IGNORE_VNO) { if (!best_entry.principal || (best_entry.vno < ent.vno)) { krb5_kt_free_entry(context, &best_entry); best_entry = ent; diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 0fe02a95d09e..55f82b147d8c 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -364,6 +364,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/t_in_ccache.c \ $(srcdir)/t_response_items.c \ $(srcdir)/t_sname_match.c \ + $(srcdir)/t_valid_times.c \ $(srcdir)/t_vfy_increds.c # Someday, when we have a "maintainer mode", do this right: @@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS) +t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS) + TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ - t_in_ccache t_cc_config t_copy_context \ - t_princ t_etypes t_vfy_increds t_response_items t_sname_match + t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \ + t_response_items t_sname_match t_valid_times check-unix: $(TEST_PROGS) $(RUN_TEST_LOCAL_CONF) ./t_kerb \ @@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS) $(RUN_TEST) ./t_response_items $(RUN_TEST) ./t_copy_context $(RUN_TEST) ./t_sname_match + $(RUN_TEST) ./t_valid_times check-pytests: t_expire_warn t_vfy_increds $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) @@ -522,8 +527,9 @@ clean: $(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \ $(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \ $(OUTPRE)t_response_items$(EXEEXT) \ - $(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \ - $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_response_items.$(OBJEXT) \ + $(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \ + $(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \ $(OUTPRE)t_parse_host_string$(EXEEXT) \ $(OUTPRE)t_parse_host_string.$(OBJEXT) diff --git a/src/lib/krb5/krb/deltat.c b/src/lib/krb5/krb/deltat.c index 2c8b90b54ce3..6e6616e99ff8 100644 --- a/src/lib/krb5/krb/deltat.c +++ b/src/lib/krb5/krb/deltat.c @@ -72,7 +72,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" @@ -153,7 +152,7 @@ static int mylex(int *intp, struct param *tmv); static int yyparse(struct param *); -#line 157 "deltat.c" /* yacc.c:339 */ +#line 156 "deltat.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -197,10 +196,10 @@ extern int yydebug; typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 129 "x-deltat.y" /* yacc.c:355 */ +#line 128 "x-deltat.y" /* yacc.c:355 */ int val; -#line 204 "deltat.c" /* yacc.c:355 */ +#line 203 "deltat.c" /* yacc.c:355 */ }; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -214,7 +213,7 @@ int yyparse (struct param *tmv); /* Copy the second part of user declarations. */ -#line 218 "deltat.c" /* yacc.c:358 */ +#line 217 "deltat.c" /* yacc.c:358 */ #ifdef short # undef short @@ -512,9 +511,9 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 143, 143, 144, 144, 145, 145, 146, 146, 147, - 148, 150, 151, 152, 153, 154, 155, 156, 157, 162, - 163, 166, 167, 170, 171 + 0, 142, 142, 143, 143, 144, 144, 145, 145, 146, + 147, 149, 150, 151, 152, 153, 154, 155, 156, 161, + 162, 165, 166, 169, 170 }; #endif @@ -1310,93 +1309,93 @@ yyreduce: switch (yyn) { case 6: -#line 145 "x-deltat.y" /* yacc.c:1646 */ +#line 144 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = - (yyvsp[0].val); } -#line 1316 "deltat.c" /* yacc.c:1646 */ +#line 1315 "deltat.c" /* yacc.c:1646 */ break; case 9: -#line 147 "x-deltat.y" /* yacc.c:1646 */ +#line 146 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = (yyvsp[0].val); } -#line 1322 "deltat.c" /* yacc.c:1646 */ +#line 1321 "deltat.c" /* yacc.c:1646 */ break; case 10: -#line 148 "x-deltat.y" /* yacc.c:1646 */ +#line 147 "x-deltat.y" /* yacc.c:1646 */ { YYERROR; } -#line 1328 "deltat.c" /* yacc.c:1646 */ +#line 1327 "deltat.c" /* yacc.c:1646 */ break; case 11: -#line 150 "x-deltat.y" /* yacc.c:1646 */ +#line 149 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-2].val), 0, 0, (yyvsp[0].val)); } -#line 1334 "deltat.c" /* yacc.c:1646 */ +#line 1333 "deltat.c" /* yacc.c:1646 */ break; case 12: -#line 151 "x-deltat.y" /* yacc.c:1646 */ +#line 150 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), 0, (yyvsp[0].val)); } -#line 1340 "deltat.c" /* yacc.c:1646 */ +#line 1339 "deltat.c" /* yacc.c:1646 */ break; case 13: -#line 152 "x-deltat.y" /* yacc.c:1646 */ +#line 151 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1346 "deltat.c" /* yacc.c:1646 */ +#line 1345 "deltat.c" /* yacc.c:1646 */ break; case 14: -#line 153 "x-deltat.y" /* yacc.c:1646 */ +#line 152 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[-1].val)); } -#line 1352 "deltat.c" /* yacc.c:1646 */ +#line 1351 "deltat.c" /* yacc.c:1646 */ break; case 15: -#line 154 "x-deltat.y" /* yacc.c:1646 */ +#line 153 "x-deltat.y" /* yacc.c:1646 */ { DO ((yyvsp[-6].val), (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1358 "deltat.c" /* yacc.c:1646 */ +#line 1357 "deltat.c" /* yacc.c:1646 */ break; case 16: -#line 155 "x-deltat.y" /* yacc.c:1646 */ +#line 154 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val)); } -#line 1364 "deltat.c" /* yacc.c:1646 */ +#line 1363 "deltat.c" /* yacc.c:1646 */ break; case 17: -#line 156 "x-deltat.y" /* yacc.c:1646 */ +#line 155 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, (yyvsp[-2].val), (yyvsp[0].val), 0); } -#line 1370 "deltat.c" /* yacc.c:1646 */ +#line 1369 "deltat.c" /* yacc.c:1646 */ break; case 18: -#line 157 "x-deltat.y" /* yacc.c:1646 */ +#line 156 "x-deltat.y" /* yacc.c:1646 */ { DO ( 0, 0, 0, (yyvsp[0].val)); } -#line 1376 "deltat.c" /* yacc.c:1646 */ +#line 1375 "deltat.c" /* yacc.c:1646 */ break; case 20: -#line 163 "x-deltat.y" /* yacc.c:1646 */ +#line 162 "x-deltat.y" /* yacc.c:1646 */ { if (HOUR_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 3600, (yyvsp[0].val)); } -#line 1383 "deltat.c" /* yacc.c:1646 */ +#line 1382 "deltat.c" /* yacc.c:1646 */ break; case 22: -#line 167 "x-deltat.y" /* yacc.c:1646 */ +#line 166 "x-deltat.y" /* yacc.c:1646 */ { if (MIN_NOT_OK((yyvsp[-2].val))) YYERROR; DO_SUM((yyval.val), (yyvsp[-2].val) * 60, (yyvsp[0].val)); } -#line 1390 "deltat.c" /* yacc.c:1646 */ +#line 1389 "deltat.c" /* yacc.c:1646 */ break; case 23: -#line 170 "x-deltat.y" /* yacc.c:1646 */ +#line 169 "x-deltat.y" /* yacc.c:1646 */ { (yyval.val) = 0; } -#line 1396 "deltat.c" /* yacc.c:1646 */ +#line 1395 "deltat.c" /* yacc.c:1646 */ break; -#line 1400 "deltat.c" /* yacc.c:1646 */ +#line 1399 "deltat.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1624,7 +1623,7 @@ yyreturn: #endif return yyresult; } -#line 173 "x-deltat.y" /* yacc.c:1906 */ +#line 172 "x-deltat.y" /* yacc.c:1906 */ #ifdef __GNUC__ diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index 6919eaf717aa..f78b47e766e1 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -1236,8 +1236,15 @@ t_walk_rtree.so t_walk_rtree.po $(OUTPRE)t_walk_rtree.$(OBJEXT): \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_walk_rtree.c t_kerb.so t_kerb.po $(OUTPRE)t_kerb.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \ - t_kerb.c + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(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/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_kerb.c t_ser.so t_ser.po $(OUTPRE)t_ser.$(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 \ @@ -1283,14 +1290,14 @@ t_pac.so t_pac.po $(OUTPRE)t_pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ t_parse_host_string.so t_parse_host_string.po $(OUTPRE)t_parse_host_string.$(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 $(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/k5-trace.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - t_parse_host_string.c + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-cmocka.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/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h t_parse_host_string.c t_princ.so t_princ.po $(OUTPRE)t_princ.$(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 \ @@ -1389,6 +1396,17 @@ t_sname_match.so t_sname_match.po $(OUTPRE)t_sname_match.$(OBJEXT): \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ t_sname_match.c +t_valid_times.so t_valid_times.po $(OUTPRE)t_valid_times.$(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 $(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/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + int-proto.h t_valid_times.c t_vfy_increds.so t_vfy_increds.po $(OUTPRE)t_vfy_increds.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/krb/fwd_tgt.c b/src/lib/krb5/krb/fwd_tgt.c index a217d4c24001..87f63b6bc4c8 100644 --- a/src/lib/krb5/krb/fwd_tgt.c +++ b/src/lib/krb5/krb/fwd_tgt.c @@ -37,8 +37,9 @@ /* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, - char *rhost, krb5_principal client, krb5_principal server, - krb5_ccache cc, int forwardable, krb5_data *outbuf) + const char *rhost, krb5_principal client, + krb5_principal server, krb5_ccache cc, int forwardable, + krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; @@ -48,8 +49,8 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; - int close_cc = 0; - int free_rhost = 0; + krb5_ccache defcc = NULL; + char *def_rhost = NULL; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; @@ -58,9 +59,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, memset(&tgt, 0, sizeof(creds)); if (cc == 0) { - if ((retval = krb5int_cc_default(context, &cc))) + if ((retval = krb5int_cc_default(context, &defcc))) goto errout; - close_cc = 1; + cc = defcc; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) @@ -131,11 +132,11 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, goto errout; } - rhost = k5memdup0(server->data[1].data, server->data[1].length, - &retval); - if (rhost == NULL) + def_rhost = k5memdup0(server->data[1].data, server->data[1].length, + &retval); + if (def_rhost == NULL) goto errout; - free_rhost = 1; + rhost = def_rhost; } retval = k5_os_hostaddr(context, rhost, &addrs); @@ -176,10 +177,9 @@ krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, errout: if (addrs) krb5_free_addresses(context, addrs); - if (close_cc) - krb5_cc_close(context, cc); - if (free_rhost) - free(rhost); + if (defcc) + krb5_cc_close(context, defcc); + free(def_rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c index 4c0a1a46120a..5b9bb9573e27 100644 --- a/src/lib/krb5/krb/gc_via_tkt.c +++ b/src/lib/krb5/krb/gc_via_tkt.c @@ -287,26 +287,27 @@ krb5int_process_tgs_reply(krb5_context context, retval = KRB5_KDCREP_MODIFIED; if ((in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.endtime > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE) && (in_cred->times.renew_till != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till)) + ts_after(dec_rep->enc_part2->times.renew_till, + in_cred->times.renew_till)) retval = KRB5_KDCREP_MODIFIED; if ((kdcoptions & KDC_OPT_RENEWABLE_OK) && (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) && (in_cred->times.endtime != 0) && - (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime)) + ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime)) retval = KRB5_KDCREP_MODIFIED; if (retval != 0) goto cleanup; if (!in_cred->times.starttime && - !in_clock_skew(dec_rep->enc_part2->times.starttime, - timestamp)) { + !ts_within(dec_rep->enc_part2->times.starttime, timestamp, + context->clockskew)) { retval = KRB5_KDCREP_SKEW; goto cleanup; } diff --git a/src/lib/krb5/krb/gen_save_subkey.c b/src/lib/krb5/krb/gen_save_subkey.c index 61f36aa3665f..bc2c46d30c22 100644 --- a/src/lib/krb5/krb/gen_save_subkey.c +++ b/src/lib/krb5/krb/gen_save_subkey.c @@ -38,7 +38,8 @@ k5_generate_and_save_subkey(krb5_context context, to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ struct { - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; } rnd_data; krb5_data d; krb5_error_code retval; diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c index 110abeb2b1bd..69900adfa046 100644 --- a/src/lib/krb5/krb/get_creds.c +++ b/src/lib/krb5/krb/get_creds.c @@ -576,14 +576,6 @@ step_referrals(krb5_context context, krb5_tkt_creds_context ctx) } if (ctx->referral_count == 1) { - /* Cache the referral TGT only if it's from the local realm. - * Make sure to note the associated authdata, if any. */ - code = krb5_copy_authdata(context, ctx->authdata, - &ctx->reply_creds->authdata); - if (code != 0) - return code; - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->reply_creds); - /* The authdata in this TGT will be copied into subsequent TGTs or the * final credentials, so we don't need to request it again. */ krb5_free_authdata(context, ctx->in_creds->authdata); @@ -816,7 +808,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx, return code; /* Check if the TGT is expired before bothering the KDC with it. */ - if (now > tgt->times.endtime) { + if (ts_after(now, tgt->times.endtime)) { krb5_free_creds(context, tgt); return KRB5KRB_AP_ERR_TKT_EXPIRED; } @@ -934,8 +926,9 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx) /* See where we wound up on the path (or off it). */ path_realm = find_realm_in_path(context, ctx, tgt_realm); if (path_realm != NULL) { - /* We got a realm on the expected path, so we can cache it. */ - (void) krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); + /* Only cache the TGT if we asked for it, to avoid duplicates. */ + if (path_realm == ctx->next_realm) + (void)krb5_cc_store_cred(context, ctx->ccache, ctx->cur_tgt); if (path_realm == ctx->last_realm) { /* We received a TGT for the target realm. */ TRACE_TKT_CREDS_TARGET_TGT(context, ctx->cur_tgt->server); diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 54badbbc32f8..47a00bf2c702 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -40,24 +40,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context, krb5_pa_data **padata); /* - * This function performs 32 bit bounded addition so we can generate - * lifetimes without overflowing krb5_int32 - */ -static krb5_int32 -krb5int_addint32 (krb5_int32 x, krb5_int32 y) -{ - if ((x > 0) && (y > (KRB5_INT32_MAX - x))) { - /* sum will be be greater than KRB5_INT32_MAX */ - return KRB5_INT32_MAX; - } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) { - /* sum will be less than KRB5_INT32_MIN */ - return KRB5_INT32_MIN; - } - - return x + y; -} - -/* * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2. If * strengthen_key is not null, combine it with the reply key as specified in * RFC 6113 section 5.4.3. Place the key used in *key_out. @@ -267,28 +249,28 @@ verify_as_reply(krb5_context context, (request->from != 0) && (request->from != as_reply->enc_part2->times.starttime)) || ((request->till != 0) && - (as_reply->enc_part2->times.endtime > request->till)) + ts_after(as_reply->enc_part2->times.endtime, request->till)) || ((request->kdc_options & KDC_OPT_RENEWABLE) && (request->rtime != 0) && - (as_reply->enc_part2->times.renew_till > request->rtime)) + ts_after(as_reply->enc_part2->times.renew_till, request->rtime)) || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && !(request->kdc_options & KDC_OPT_RENEWABLE) && (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && (request->till != 0) && - (as_reply->enc_part2->times.renew_till > request->till)) + ts_after(as_reply->enc_part2->times.renew_till, request->till)) ) { return KRB5_KDCREP_MODIFIED; } if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { - time_offset = as_reply->enc_part2->times.authtime - time_now; + time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now); retval = krb5_set_time_offsets(context, time_offset, 0); if (retval) return retval; } else { if ((request->from == 0) && - (labs(as_reply->enc_part2->times.starttime - time_now) - > context->clockskew)) + !ts_within(as_reply->enc_part2->times.starttime, time_now, + context->clockskew)) return (KRB5_KDCREP_SKEW); } return 0; @@ -583,7 +565,7 @@ krb5_init_creds_free(krb5_context context, k5_response_items_free(ctx->rctx.items); free(ctx->in_tkt_service); zapfree(ctx->gakpw.storage.data, ctx->gakpw.storage.length); - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); krb5_free_error(context, ctx->err_reply); krb5_free_pa_data(context, ctx->err_padata); krb5_free_cred_contents(context, &ctx->cred); @@ -593,7 +575,9 @@ krb5_init_creds_free(krb5_context context, krb5_free_data(context, ctx->inner_request_body); krb5_free_data(context, ctx->encoded_previous_request); krb5int_fast_free_state(context, ctx->fast_state); - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_data_contents(context, &ctx->salt); krb5_free_data_contents(context, &ctx->s2kparams); krb5_free_keyblock_contents(context, &ctx->as_key); @@ -760,23 +744,6 @@ k5_init_creds_current_time(krb5_context context, krb5_init_creds_context ctx, } } -/* Choose a random nonce for ctx->request. */ -static krb5_error_code -pick_nonce(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code code = 0; - unsigned char random_buf[4]; - krb5_data random_data = make_data(random_buf, 4); - - /* We incorrectly encode this as signed, so make sure we use an unsigned - * value to avoid interoperability issues. */ - code = krb5_c_random_make_octets(context, &random_data); - if (code != 0) - return code; - ctx->request->nonce = 0x7fffffff & load_32_n(random_buf); - return 0; -} - /* Set the timestamps for ctx->request based on the desired lifetimes. */ static krb5_error_code set_request_times(krb5_context context, krb5_init_creds_context ctx) @@ -790,16 +757,16 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return code; /* Omit request start time unless the caller explicitly asked for one. */ - from = krb5int_addint32(now, ctx->start_time); + from = ts_incr(now, ctx->start_time); if (ctx->start_time != 0) ctx->request->from = from; - ctx->request->till = krb5int_addint32(from, ctx->tkt_life); + ctx->request->till = ts_incr(from, ctx->tkt_life); if (ctx->renew_life > 0) { /* Don't ask for a smaller renewable time than the lifetime. */ - ctx->request->rtime = krb5int_addint32(from, ctx->renew_life); - if (ctx->request->rtime < ctx->request->till) + ctx->request->rtime = ts_incr(from, ctx->renew_life); + if (ts_after(ctx->request->till, ctx->request->rtime)) ctx->request->rtime = ctx->request->till; ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK; } else { @@ -809,6 +776,31 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) return 0; } +static void +read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_error_code ret; + krb5_data config; + char *tmp, *p; + krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); + + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + if (in_ccache == NULL) + return; + memset(&config, 0, sizeof(config)); + if (krb5_cc_get_config(context, in_ccache, ctx->request->server, + KRB5_CC_CONF_PA_TYPE, &config) != 0) + return; + tmp = k5memdup0(config.data, config.length, &ret); + krb5_free_data_contents(context, &config); + if (tmp == NULL) + return; + ctx->allowed_preauth_type = strtol(tmp, &p, 10); + if (p == NULL || *p != '\0') + ctx->allowed_preauth_type = KRB5_PADATA_NONE; + free(tmp); +} + /** * Throw away any pre-authentication realm state and begin with a * unauthenticated or optimistically authenticated request. If fast_upgrade is @@ -820,11 +812,15 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, { krb5_error_code code = 0; - krb5_free_pa_data(context, ctx->preauth_to_use); + krb5_free_pa_data(context, ctx->optimistic_padata); + krb5_free_pa_data(context, ctx->method_padata); + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); krb5_free_error(context, ctx->err_reply); - ctx->preauth_to_use = ctx->err_padata = NULL; + ctx->optimistic_padata = ctx->method_padata = ctx->more_padata = NULL; + ctx->err_padata = NULL; ctx->err_reply = NULL; + ctx->selected_preauth_type = KRB5_PADATA_NONE; krb5int_fast_free_state(context, ctx->fast_state); ctx->fast_state = NULL; @@ -834,14 +830,14 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, if (fast_upgrade) ctx->fast_state->fast_state_flags |= KRB5INT_FAST_DO_FAST; - k5_preauth_request_context_fini(context); - k5_preauth_request_context_init(context); + k5_preauth_request_context_fini(context, ctx); + k5_preauth_request_context_init(context, ctx); krb5_free_data(context, ctx->outer_request_body); ctx->outer_request_body = NULL; if (ctx->opt->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { code = make_preauth_list(context, ctx->opt->preauth_list, ctx->opt->preauth_list_length, - &ctx->preauth_to_use); + &ctx->optimistic_padata); if (code) goto cleanup; } @@ -867,6 +863,11 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx, &ctx->outer_request_body); if (code != 0) goto cleanup; + + /* Read the allowed preauth type for this server principal from the input + * ccache, if the application supplied one. */ + read_allowed_preauth_type(context, ctx); + cleanup: return code; } @@ -1172,31 +1173,6 @@ init_creds_validate_reply(krb5_context context, return 0; } -static void -read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx) -{ - krb5_error_code ret; - krb5_data config; - char *tmp, *p; - krb5_ccache in_ccache = k5_gic_opt_get_in_ccache(ctx->opt); - - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - if (in_ccache == NULL) - return; - memset(&config, 0, sizeof(config)); - if (krb5_cc_get_config(context, in_ccache, ctx->request->server, - KRB5_CC_CONF_PA_TYPE, &config) != 0) - return; - tmp = k5memdup0(config.data, config.length, &ret); - krb5_free_data_contents(context, &config); - if (tmp == NULL) - return; - ctx->allowed_preauth_type = strtol(tmp, &p, 10); - if (p == NULL || *p != '\0') - ctx->allowed_preauth_type = KRB5_PADATA_NONE; - free(tmp); -} - static krb5_error_code save_selected_preauth_type(krb5_context context, krb5_ccache ccache, krb5_init_creds_context ctx) @@ -1313,6 +1289,9 @@ init_creds_step_request(krb5_context context, krb5_data *out) { krb5_error_code code; + krb5_preauthtype pa_type; + struct errinfo save = EMPTY_ERRINFO; + uint32_t rcode = (ctx->err_reply == NULL) ? 0 : ctx->err_reply->error; if (ctx->loopcount >= MAX_IN_TKT_LOOPS) { code = KRB5_GET_IN_TKT_LOOP; @@ -1320,7 +1299,7 @@ init_creds_step_request(krb5_context context, } /* RFC 6113 requires a new nonce for the inner request on each try. */ - code = pick_nonce(context, ctx); + code = k5_generate_nonce(context, &ctx->request->nonce); if (code != 0) goto cleanup; @@ -1335,11 +1314,6 @@ init_creds_step_request(krb5_context context, if (code) goto cleanup; - /* Read the allowed patype for this server principal from the in_ccache, - * if the application supplied one. */ - read_allowed_preauth_type(context, ctx); - ctx->selected_preauth_type = KRB5_PADATA_NONE; - /* * Read cached preauth configuration data for this server principal from * the in_ccache, if the application supplied one, and delete any that was @@ -1348,32 +1322,65 @@ init_creds_step_request(krb5_context context, read_cc_config_in_data(context, ctx); clear_cc_config_out_data(context, ctx); - if (ctx->err_reply == NULL) { - /* Either our first attempt, or retrying after KDC_ERR_PREAUTH_REQUIRED - * or KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ - code = k5_preauth(context, ctx, ctx->preauth_to_use, - ctx->preauth_required, &ctx->request->padata, - &ctx->selected_preauth_type); - if (code != 0) - goto cleanup; - } else { - if (ctx->preauth_to_use != NULL) { - /* - * Retry after an error other than PREAUTH_NEEDED, - * using ctx->err_padata to figure out what to change. - */ - code = k5_preauth_tryagain(context, ctx, ctx->preauth_to_use, - &ctx->request->padata); - } else { - /* No preauth supplied, so can't query the plugins. */ - code = KRB5KRB_ERR_GENERIC; + ctx->request->padata = NULL; + if (ctx->optimistic_padata != NULL) { + /* Our first attempt, using an optimistic padata list. */ + TRACE_INIT_CREDS_PREAUTH_OPTIMISTIC(context); + code = k5_preauth(context, ctx, ctx->optimistic_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + krb5_free_pa_data(context, ctx->optimistic_padata); + ctx->optimistic_padata = NULL; + if (code) { + /* Make an unauthenticated request, and possibly try again using + * the same mechanisms as we tried optimistically. */ + k5_reset_preauth_types_tried(ctx); + krb5_clear_error_message(context); + code = 0; } - if (code != 0) { - /* couldn't come up with anything better */ + } if (ctx->more_padata != NULL) { + /* Continuing after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ + TRACE_INIT_CREDS_PREAUTH_MORE(context, ctx->selected_preauth_type); + code = k5_preauth(context, ctx, ctx->more_padata, TRUE, + &ctx->request->padata, &pa_type); + } else if (rcode == KDC_ERR_PREAUTH_FAILED) { + /* Report the KDC-side failure code if we can't try another mech. */ + code = KRB5KDC_ERR_PREAUTH_FAILED; + } else if (rcode && rcode != KDC_ERR_PREAUTH_REQUIRED) { + /* Retrying after an error (possibly mechanism-specific), using error + * padata to figure out what to change. */ + TRACE_INIT_CREDS_PREAUTH_TRYAGAIN(context, ctx->err_reply->error, + ctx->selected_preauth_type); + code = k5_preauth_tryagain(context, ctx, ctx->selected_preauth_type, + ctx->err_reply, ctx->err_padata, + &ctx->request->padata); + if (code) { + krb5_clear_error_message(context); code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5; + } + } + /* Don't continue after a keyboard interrupt. */ + if (code == KRB5_LIBOS_PWDINTR) + goto cleanup; + if (code) { + /* See if we can try a different preauth mech before giving up. */ + k5_save_ctx_error(context, code, &save); + ctx->selected_preauth_type = KRB5_PADATA_NONE; + } + + if (ctx->request->padata == NULL && ctx->method_padata != NULL) { + /* Retrying after KDC_ERR_PREAUTH_REQUIRED, or trying again with a + * different mechanism after a failure. */ + TRACE_INIT_CREDS_PREAUTH(context); + code = k5_preauth(context, ctx, ctx->method_padata, TRUE, + &ctx->request->padata, &ctx->selected_preauth_type); + if (code) { + if (save.code != 0) + code = k5_restore_ctx_error(context, &save); goto cleanup; } } + if (ctx->request->padata == NULL) + TRACE_INIT_CREDS_PREAUTH_NONE(context); /* Remember when we sent this request (after any preauth delay). */ ctx->request_time = time(NULL); @@ -1382,8 +1389,6 @@ init_creds_step_request(krb5_context context, krb5_free_data(context, ctx->encoded_previous_request); ctx->encoded_previous_request = NULL; } - if (ctx->request->padata) - ctx->sent_nontrivial_preauth = TRUE; if (ctx->enc_pa_rep_permitted) { code = add_padata(&ctx->request->padata, KRB5_ENCPADATA_REQ_ENC_PA_REP, NULL, 0); @@ -1411,6 +1416,7 @@ init_creds_step_request(krb5_context context, cleanup: krb5_free_pa_data(context, ctx->request->padata); ctx->request->padata = NULL; + k5_clear_error(&save); return code; } @@ -1438,7 +1444,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx, if (k5_time_with_offset(0, 0, &now, &usec) != 0) return; - ctx->pa_offset = kdc_time - now; + ctx->pa_offset = ts_delta(kdc_time, now); ctx->pa_offset_usec = kdc_usec - usec; ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ? AUTH_OFFSET : UNAUTH_OFFSET; @@ -1463,6 +1469,18 @@ is_referral(krb5_context context, krb5_error *err, krb5_principal client) return !krb5_realm_compare(context, err->client, client); } +/* Transfer error padata to method data in ctx and sort it according to + * configuration. */ +static krb5_error_code +accept_method_data(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_free_pa_data(context, ctx->method_padata); + ctx->method_padata = ctx->err_padata; + ctx->err_padata = NULL; + return sort_krb5_padata_sequence(context, &ctx->request->client->realm, + ctx->method_padata); +} + static krb5_error_code init_creds_step_reply(krb5_context context, krb5_init_creds_context ctx, @@ -1492,8 +1510,9 @@ init_creds_step_reply(krb5_context context, ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL; if (ctx->err_reply != NULL) { + krb5_free_pa_data(context, ctx->more_padata); krb5_free_pa_data(context, ctx->err_padata); - ctx->err_padata = NULL; + ctx->more_padata = ctx->err_padata = NULL; code = krb5int_fast_process_error(context, ctx->fast_state, &ctx->err_reply, &ctx->err_padata, &retry); @@ -1508,7 +1527,7 @@ init_creds_step_reply(krb5_context context, ctx->restarted = TRUE; code = restart_init_creds_loop(context, ctx, TRUE); } else if (!ctx->restarted && reply_code == KDC_ERR_PREAUTH_FAILED && - !ctx->sent_nontrivial_preauth) { + ctx->selected_preauth_type == KRB5_PADATA_NONE) { /* The KDC didn't like our informational padata (probably a pre-1.7 * MIT krb5 KDC). Retry without it. */ ctx->enc_pa_rep_permitted = FALSE; @@ -1519,23 +1538,30 @@ init_creds_step_reply(krb5_context context, * FAST upgrade. */ ctx->restarted = FALSE; code = restart_init_creds_loop(context, ctx, FALSE); - } else if ((reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED || - reply_code == KDC_ERR_PREAUTH_REQUIRED) && retry) { - /* reset the list of preauth types to try */ - k5_reset_preauth_types_tried(context); - krb5_free_pa_data(context, ctx->preauth_to_use); - ctx->preauth_to_use = ctx->err_padata; - ctx->err_padata = NULL; + } else if (reply_code == KDC_ERR_PREAUTH_REQUIRED && retry) { note_req_timestamp(context, ctx, ctx->err_reply->stime, ctx->err_reply->susec); - /* This will trigger a new call to k5_preauth(). */ - krb5_free_error(context, ctx->err_reply); - ctx->err_reply = NULL; - code = sort_krb5_padata_sequence(context, - &ctx->request->client->realm, - ctx->preauth_to_use); - ctx->preauth_required = TRUE; - + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_PREAUTH_FAILED && retry) { + note_req_timestamp(context, ctx, ctx->err_reply->stime, + ctx->err_reply->susec); + if (ctx->method_padata == NULL) { + /* Optimistic preauth failed on the KDC. Allow all mechanisms + * to be tried again using method data. */ + k5_reset_preauth_types_tried(ctx); + } else { + /* Don't try again with the mechanism that failed. */ + code = k5_preauth_note_failed(ctx, ctx->selected_preauth_type); + if (code) + goto cleanup; + } + ctx->selected_preauth_type = KRB5_PADATA_NONE; + /* Accept or update method data if the KDC sent it. */ + if (ctx->err_padata != NULL) + code = accept_method_data(context, ctx); + } else if (reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED && retry) { + ctx->more_padata = ctx->err_padata; + ctx->err_padata = NULL; } else if (canon_flag && is_referral(context, ctx->err_reply, ctx->request->client)) { TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm); @@ -1548,14 +1574,13 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* Reset per-realm negotiation state. */ ctx->restarted = FALSE; - ctx->sent_nontrivial_preauth = FALSE; ctx->enc_pa_rep_permitted = TRUE; code = restart_init_creds_loop(context, ctx, FALSE); } else { - if (retry) { + if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) { code = 0; } else { - /* error + no hints = give up */ + /* error + no hints (or no preauth mech) = give up */ code = (krb5_error_code)reply_code + ERROR_TABLE_BASE_krb5; } } @@ -1573,7 +1598,6 @@ init_creds_step_reply(krb5_context context, goto cleanup; /* process any preauth data in the as_reply */ - k5_reset_preauth_types_tried(context); code = krb5int_fast_process_response(context, ctx->fast_state, ctx->reply, &strengthen_key); if (code != 0) @@ -1658,7 +1682,7 @@ init_creds_step_reply(krb5_context context, k5_prependmsg(context, code, _("Failed to store credentials")); } - k5_preauth_request_context_fini(context); + k5_preauth_request_context_fini(context, ctx); /* success */ ctx->complete = TRUE; @@ -1685,7 +1709,7 @@ krb5_init_creds_step(krb5_context context, krb5_data *realm, unsigned int *flags) { - krb5_error_code code = 0, code2; + krb5_error_code code, code2; *flags = 0; @@ -1698,6 +1722,10 @@ krb5_init_creds_step(krb5_context context, if (ctx->complete) return EINVAL; + code = k5_preauth_check_context(context, ctx); + if (code) + return code; + if (in->length != 0) { code = init_creds_step_reply(context, ctx, in); if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) { @@ -1806,7 +1834,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, krb5_creds *creds) { int i; - krb5_int32 starttime; + krb5_timestamp starttime; + krb5_deltat lifetime; krb5_get_init_creds_opt *opt; krb5_error_code retval; @@ -1838,7 +1867,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, if (retval) goto cleanup; if (creds->times.starttime) starttime = creds->times.starttime; - krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime); + lifetime = ts_delta(creds->times.endtime, starttime); + krb5_get_init_creds_opt_set_tkt_life(opt, lifetime); } *out = opt; return 0; diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index 3be44d5cd756..ccbe1a65fa5a 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -12,7 +12,7 @@ #include <TargetConditionals.h> #endif -/* Match struct packing of krb5_get_init_creds_opt on MacOS X. */ +/* Match struct packing of krb5_get_init_creds_opt on macOS. */ #if TARGET_OS_MAC #pragma pack(push,2) #endif diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c index 6f3a29f2c423..3565a7c4c77a 100644 --- a/src/lib/krb5/krb/gic_pwd.c +++ b/src/lib/krb5/krb/gic_pwd.c @@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; if (!is_last_req && - (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60)) + (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60)) return; if (!prompter) @@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, if (ret != 0) return; - delta = pw_exp - now; + delta = ts_delta(pw_exp, now); if (delta < 3600) { snprintf(banner, sizeof(banner), _("Warning: Your password will expire in less than one hour " diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index 38c01c775b6f..fe769685ba09 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -6,6 +6,8 @@ #include "k5-json.h" #include "int-proto.h" +typedef struct krb5_preauth_req_context_st *krb5_preauth_req_context; + struct krb5_responder_context_st { k5_response_items *items; }; @@ -48,7 +50,9 @@ struct _krb5_init_creds_context { krb5_data *inner_request_body; /**< For preauth */ krb5_data *encoded_previous_request; struct krb5int_fast_request_state *fast_state; - krb5_pa_data **preauth_to_use; + krb5_pa_data **optimistic_padata; /* from gic options */ + krb5_pa_data **method_padata; /* from PREAUTH_REQUIRED or PREAUTH_FAILED */ + krb5_pa_data **more_padata; /* from MORE_PREAUTH_DATA_REQUIRED */ krb5_boolean default_salt; krb5_data salt; krb5_data s2kparams; @@ -56,8 +60,6 @@ struct _krb5_init_creds_context { krb5_enctype etype; krb5_boolean enc_pa_rep_permitted; krb5_boolean restarted; - krb5_boolean sent_nontrivial_preauth; - krb5_boolean preauth_required; struct krb5_responder_context_st rctx; krb5_preauthtype selected_preauth_type; krb5_preauthtype allowed_preauth_type; @@ -67,6 +69,7 @@ struct _krb5_init_creds_context { krb5_timestamp pa_offset; krb5_int32 pa_offset_usec; enum { NO_OFFSET = 0, UNAUTH_OFFSET, AUTH_OFFSET } pa_offset_state; + krb5_preauth_req_context preauth_reqctx; }; krb5_error_code diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c index cf226fdbabc0..4246c5dd274f 100644 --- a/src/lib/krb5/krb/init_ctx.c +++ b/src/lib/krb5/krb/init_ctx.c @@ -139,7 +139,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags, krb5_context ctx = 0; krb5_error_code retval; struct { - krb5_int32 now, now_usec; + krb5_timestamp now; + krb5_int32 now_usec; long pid; } seed_data; krb5_data seed; diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 6da74858e210..cda9010e34a3 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -83,8 +83,6 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options, krb5_creds *in_creds, krb5_creds *mcreds, krb5_flags *fields); -#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) - #define IS_TGS_PRINC(p) ((p)->length == 2 && \ data_eq_string((p)->data[0], KRB5_TGS_NAME)) @@ -102,6 +100,9 @@ krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt, krb5_keyblock **out_subkey); krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out); + +krb5_error_code k5_make_tgs_req(krb5_context context, struct krb5int_fast_request_state *, krb5_creds *tkt, krb5_flags kdcoptions, krb5_address *const *address, krb5_pa_data **in_padata, @@ -187,7 +188,8 @@ k5_preauth(krb5_context context, krb5_init_creds_context ctx, krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out); + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out); void k5_init_preauth_context(krb5_context context); @@ -196,17 +198,25 @@ void k5_free_preauth_context(krb5_context context); void -k5_reset_preauth_types_tried(krb5_context context); +k5_reset_preauth_types_tried(krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type); void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *request); void -k5_preauth_request_context_init(krb5_context context); +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx); void -k5_preauth_request_context_fini(krb5_context context); +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx); + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx); krb5_error_code k5_response_items_new(k5_response_items **ri_out); diff --git a/src/lib/krb5/krb/mk_req.c b/src/lib/krb5/krb/mk_req.c index 542ef6d4aee5..162c05b5cbd9 100644 --- a/src/lib/krb5/krb/mk_req.c +++ b/src/lib/krb5/krb/mk_req.c @@ -48,8 +48,9 @@ krb5_error_code KRB5_CALLCONV krb5_mk_req(krb5_context context, krb5_auth_context *auth_context, - krb5_flags ap_req_options, char *service, char *hostname, - krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf) + krb5_flags ap_req_options, const char *service, + const char *hostname, krb5_data *in_data, krb5_ccache ccache, + krb5_data *outbuf) { krb5_error_code retval; krb5_principal server; diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index 9098927b5acf..0eb19e6bb464 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds) abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime; - if (abstime > KRB5_INT32_MAX) + if (abstime > UINT32_MAX) return ERANGE; *elapsedSeconds = abstime; @@ -436,8 +436,7 @@ k5_pac_validate_client(krb5_context context, pac_princname_length % 2) return ERANGE; - ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, - &pac_princname, NULL); + ret = k5_utf16le_to_utf8(p, pac_princname_length, &pac_princname); if (ret != 0) return ret; @@ -792,8 +791,8 @@ mspac_verify(krb5_context kcontext, * If the above verification failed, don't fail the whole authentication, * just don't mark the PAC as verified. A checksum mismatch can occur if * the PAC was copied from a cross-realm TGT by an ignorant KDC, and Apple - * Mac OS X Server Open Directory (as of 10.6) generates PACs with no - * server checksum at all. + * macOS Server Open Directory (as of 10.6) generates PACs with no server + * checksum at all. */ return 0; } diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c index d40df45f99e8..c94899c96a79 100644 --- a/src/lib/krb5/krb/pac_sign.c +++ b/src/lib/krb5/krb/pac_sign.c @@ -38,8 +38,8 @@ k5_insert_client_info(krb5_context context, krb5_error_code ret; krb5_data client_info; char *princ_name_utf8 = NULL; - unsigned char *princ_name_ucs2 = NULL, *p; - size_t princ_name_ucs2_len = 0; + unsigned char *princ_name_utf16 = NULL, *p; + size_t princ_name_utf16_len = 0; uint64_t nt_authtime; /* If we already have a CLIENT_INFO buffer, then just validate it */ @@ -54,13 +54,12 @@ k5_insert_client_info(krb5_context context, if (ret != 0) goto cleanup; - ret = krb5int_utf8s_to_ucs2les(princ_name_utf8, - &princ_name_ucs2, - &princ_name_ucs2_len); + ret = k5_utf8_to_utf16le(princ_name_utf8, &princ_name_utf16, + &princ_name_utf16_len); if (ret != 0) goto cleanup; - client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len; + client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_utf16_len; client_info.data = NULL; ret = k5_pac_add_buffer(context, pac, KRB5_PAC_CLIENT_INFO, @@ -75,16 +74,16 @@ k5_insert_client_info(krb5_context context, store_64_le(nt_authtime, p); p += 8; - /* copy in number of UCS-2 characters in principal name */ - store_16_le(princ_name_ucs2_len, p); + /* copy in number of UTF-16 bytes in principal name */ + store_16_le(princ_name_utf16_len, p); p += 2; /* copy in principal name */ - memcpy(p, princ_name_ucs2, princ_name_ucs2_len); + memcpy(p, princ_name_utf16, princ_name_utf16_len); cleanup: - if (princ_name_ucs2 != NULL) - free(princ_name_ucs2); + if (princ_name_utf16 != NULL) + free(princ_name_utf16); krb5_free_unparsed_name(context, princ_name_utf8); return ret; diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c index 7d64b7c7eda9..31aaf661d9af 100644 --- a/src/lib/krb5/krb/plugin.c +++ b/src/lib/krb5/krb/plugin.c @@ -57,7 +57,10 @@ const char *interface_names[] = { "hostrealm", "audit", "tls", - "kdcauthdata" + "kdcauthdata", + "certauth", + "kadm5_auth", + "kdcpolicy", }; /* Return the context's interface structure for id, or NULL if invalid. */ diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ca26fb0e3fa5..6b96fa135e1a 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -46,14 +46,18 @@ typedef struct { struct krb5_clpreauth_vtable_st vt; krb5_clpreauth_moddata data; - krb5_clpreauth_modreq req; } *clpreauth_handle; struct krb5_preauth_context_st { - krb5_preauthtype *tried; clpreauth_handle *handles; }; +struct krb5_preauth_req_context_st { + krb5_context orig_context; + krb5_preauthtype *failed; + krb5_clpreauth_modreq *modreqs; +}; + /* Release the memory used by a list of handles. */ static void free_handles(krb5_context context, clpreauth_handle *handles) @@ -71,21 +75,44 @@ free_handles(krb5_context context, clpreauth_handle *handles) free(handles); } -/* Find the handle in handles which can process pa_type. */ -static clpreauth_handle -find_module(clpreauth_handle *handles, krb5_preauthtype pa_type) +/* Return an index into handles which can process pa_type, or -1 if none is + * found found. */ +static int +search_module_list(clpreauth_handle *handles, krb5_preauthtype pa_type) { - clpreauth_handle *hp, h; - krb5_preauthtype *tp; + clpreauth_handle h; + int i, j; - for (hp = handles; *hp != NULL; hp++) { - h = *hp; - for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - if (*tp == pa_type) - return h; + for (i = 0; handles[i] != NULL; i++) { + h = handles[i]; + for (j = 0; h->vt.pa_type_list[j] != 0; j++) { + if (h->vt.pa_type_list[j] == pa_type) + return i; } } - return FALSE; + return -1; +} + +/* Find the handle which can process pa_type, or NULL if none is found. On + * success, set *modreq_out to the corresponding per-request module data. */ +static clpreauth_handle +find_module(krb5_context context, krb5_init_creds_context ctx, + krb5_preauthtype pa_type, krb5_clpreauth_modreq *modreq_out) +{ + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + int i; + + *modreq_out = NULL; + if (pctx == NULL || reqctx == NULL) + return NULL; + + i = search_module_list(pctx->handles, pa_type); + if (i == -1) + return NULL; + + *modreq_out = reqctx->modreqs[i]; + return pctx->handles[i]; } /* Initialize the preauth state for a krb5 context. */ @@ -93,7 +120,8 @@ void k5_init_preauth_context(krb5_context context) { krb5_plugin_initvt_fn *modules = NULL, *mod; - clpreauth_handle *list = NULL, h, h2; + clpreauth_handle *list = NULL, h; + int i; size_t count; krb5_preauthtype *tp; @@ -140,9 +168,10 @@ k5_init_preauth_context(krb5_context context) /* Check for a preauth type conflict with an existing module. */ for (tp = h->vt.pa_type_list; *tp != 0; tp++) { - h2 = find_module(list, *tp); - if (h2 != NULL) { - TRACE_PREAUTH_CONFLICT(context, h->vt.name, h2->vt.name, *tp); + i = search_module_list(list, *tp); + if (i != -1) { + TRACE_PREAUTH_CONFLICT(context, h->vt.name, list[i]->vt.name, + *tp); break; } } @@ -161,10 +190,9 @@ k5_init_preauth_context(krb5_context context) list[count] = NULL; /* Place the constructed preauth context into the krb5 context. */ - context->preauth_context = malloc(sizeof(struct krb5_preauth_context_st)); + context->preauth_context = malloc(sizeof(*context->preauth_context)); if (context->preauth_context == NULL) goto cleanup; - context->preauth_context->tried = NULL; context->preauth_context->handles = list; list = NULL; @@ -173,22 +201,35 @@ cleanup: free_handles(context, list); } -/* - * Reset the memory of which preauth types we have already tried, because we - * are entering a new phase of padata processing (such as the padata in an - * AS-REP). - */ +/* Reset the memory of which preauth types we have already tried. */ void -k5_reset_preauth_types_tried(krb5_context context) +k5_reset_preauth_types_tried(krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; - if (pctx == NULL) + if (reqctx == NULL) return; - free(pctx->tried); - pctx->tried = NULL; + free(reqctx->failed); + reqctx->failed = NULL; } +/* Add pa_type to the list of types which has previously failed. */ +krb5_error_code +k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + krb5_preauthtype *newptr; + size_t i; + + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++); + newptr = realloc(reqctx->failed, (i + 2) * sizeof(*newptr)); + if (newptr == NULL) + return ENOMEM; + reqctx->failed = newptr; + reqctx->failed[i] = pa_type; + reqctx->failed[i + 1] = 0; + return 0; +} /* Free the per-krb5_context preauth_context. This means clearing any * plugin-specific context which may have been created, and then @@ -196,11 +237,10 @@ k5_reset_preauth_types_tried(krb5_context context) void k5_free_preauth_context(krb5_context context) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; if (pctx == NULL) return; - free(pctx->tried); free_handles(context, pctx->handles); free(pctx); context->preauth_context = NULL; @@ -209,10 +249,13 @@ k5_free_preauth_context(krb5_context context) /* Initialize the per-AS-REQ context. This means calling the client_req_init * function to give the plugin a chance to allocate a per-request context. */ void -k5_preauth_request_context_init(krb5_context context) +k5_preauth_request_context_init(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + clpreauth_handle h; + krb5_preauth_req_context reqctx; + size_t count, i; if (pctx == NULL) { k5_init_preauth_context(context); @@ -220,30 +263,63 @@ k5_preauth_request_context_init(krb5_context context) if (pctx == NULL) return; } - k5_reset_preauth_types_tried(context); - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; + + reqctx = calloc(1, sizeof(*reqctx)); + if (reqctx == NULL) + return; + reqctx->orig_context = context; + + /* Create an array of per-request module data objects corresponding to the + * preauth context's array of handles. */ + for (count = 0; pctx->handles[count] != NULL; count++); + reqctx->modreqs = calloc(count, sizeof(*reqctx->modreqs)); + for (i = 0; i < count; i++) { + h = pctx->handles[i]; if (h->vt.request_init != NULL) - h->vt.request_init(context, h->data, &h->req); + h->vt.request_init(context, h->data, &reqctx->modreqs[i]); } + ctx->preauth_reqctx = reqctx; } /* Free the per-AS-REQ context. This means clearing any request-specific * context which the plugin may have created. */ void -k5_preauth_request_context_fini(krb5_context context) +k5_preauth_request_context_fini(krb5_context context, + krb5_init_creds_context ctx) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - clpreauth_handle *hp, h; + krb5_preauth_context pctx = context->preauth_context; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; + clpreauth_handle h; - if (pctx == NULL) + if (reqctx == NULL) return; - for (hp = pctx->handles; *hp != NULL; hp++) { - h = *hp; - if (h->req != NULL && h->vt.request_fini != NULL) - h->vt.request_fini(context, h->data, h->req); - h->req = NULL; + if (reqctx->orig_context == context && pctx != NULL) { + for (i = 0; pctx->handles[i] != NULL; i++) { + h = pctx->handles[i]; + if (reqctx->modreqs[i] != NULL && h->vt.request_fini != NULL) + h->vt.request_fini(context, h->data, reqctx->modreqs[i]); + } + } else { + TRACE_PREAUTH_WRONG_CONTEXT(context); + } + free(reqctx->modreqs); + free(reqctx->failed); + free(reqctx); + ctx->preauth_reqctx = NULL; +} + +krb5_error_code +k5_preauth_check_context(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + + if (reqctx != NULL && reqctx->orig_context != context) { + k5_setmsg(context, EINVAL, + _("krb5_init_creds calls must use same library context")); + return EINVAL; } + return 0; } /* Return 1 if pa_type is a real preauthentication mechanism according to the @@ -259,6 +335,7 @@ clpreauth_is_real(krb5_context context, clpreauth_handle h, static krb5_error_code clpreauth_prep_questions(krb5_context context, clpreauth_handle h, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *req, krb5_data *req_body, @@ -266,35 +343,35 @@ clpreauth_prep_questions(krb5_context context, clpreauth_handle h, { if (h->vt.prep_questions == NULL) return 0; - return h->vt.prep_questions(context, h->data, h->req, opt, cb, rock, req, + return h->vt.prep_questions(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data); } static krb5_error_code clpreauth_process(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_pa_data *pa_data, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { - return h->vt.process(context, h->data, h->req, opt, cb, rock, req, + return h->vt.process(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_data, prompter, prompter_data, pa_data_out); } static krb5_error_code clpreauth_tryagain(krb5_context context, clpreauth_handle h, - krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, - krb5_clpreauth_rock rock, krb5_kdc_req *req, - krb5_data *req_body, krb5_data *prev_req, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *req_body, krb5_data *prev_req, krb5_preauthtype pa_type, krb5_error *error, krb5_pa_data **error_padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { if (h->vt.tryagain == NULL) return 0; - return h->vt.tryagain(context, h->data, h->req, opt, cb, rock, req, + return h->vt.tryagain(context, h->data, modreq, opt, cb, rock, req, req_body, prev_req, pa_type, error, error_padata, prompter, prompter_data, pa_data_out); } @@ -420,7 +497,7 @@ responder_get_answer(krb5_context context, krb5_clpreauth_rock rock, krb5_init_creds_context ctx = (krb5_init_creds_context)rock; /* Don't let plugins get the raw password. */ - if (question && strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) + if (strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) return NULL; return k5_response_items_get_answer(ctx->rctx.items, question); } @@ -495,7 +572,7 @@ void k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt, krb5_kdc_req *req) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_enctype *ep; @@ -548,28 +625,17 @@ pa_type_allowed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) pa_type == ctx->allowed_preauth_type; } -/* - * If pa_type has already been tried as a real preauth type for this - * authentication, return true. Otherwise ass pa_type to the list of tried - * types and return false. - */ +/* Return true if pa_type previously failed during this authentication. */ static krb5_boolean -already_tried(krb5_context context, krb5_preauthtype pa_type) +previously_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; - size_t count; - krb5_preauthtype *newptr; + krb5_preauth_req_context reqctx = ctx->preauth_reqctx; + size_t i; - for (count = 0; pctx->tried != NULL && pctx->tried[count] != 0; count++) { - if (pctx->tried[count] == pa_type) + for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++) { + if (reqctx->failed[i] == pa_type) return TRUE; } - newptr = realloc(pctx->tried, (count + 2) * sizeof(*newptr)); - if (newptr == NULL) - return FALSE; - pctx->tried = newptr; - pctx->tried[count] = pa_type; - pctx->tried[count + 1] = ENCTYPE_NULL; return FALSE; } @@ -580,16 +646,13 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data ***out_pa_list, int *out_pa_list_size, krb5_preauthtype *out_type) { - struct krb5_preauth_context_st *pctx = context->preauth_context; struct errinfo save = EMPTY_ERRINFO; krb5_pa_data *pa, **pa_ptr, **mod_pa; krb5_error_code ret = 0; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int real, i; - if (pctx == NULL) - return ENOENT; - /* Process all informational padata types, then the first real preauth type * we succeed on. */ for (real = 0; real <= 1; real++) { @@ -598,17 +661,17 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Restrict real mechanisms to the chosen one if we have one. */ if (real && !pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; /* Make sure this type is for the current pass. */ if (clpreauth_is_real(context, h, pa->pa_type) != real) continue; - /* Only try a real mechanism once per authentication. */ - if (real && already_tried(context, pa->pa_type)) + /* Don't try a real mechanism again after failure. */ + if (real && previously_failed(ctx, pa->pa_type)) continue; mod_pa = NULL; - ret = clpreauth_process(context, h, ctx->opt, &callbacks, + ret = clpreauth_process(context, h, modreq, ctx->opt, &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa, @@ -625,6 +688,9 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, } free(mod_pa); } + /* Don't continue to try mechanisms after a keyboard interrupt. */ + if (ret == KRB5_LIBOS_PWDINTR) + goto cleanup; if (ret == 0 && real) { /* Stop now and record which real padata type we answered. */ *out_type = pa->pa_type; @@ -633,6 +699,12 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx, /* Save the first error we get from a real preauth type. */ k5_save_ctx_error(context, ret, &save); } + if (real && ret) { + /* Don't try this mechanism again for this authentication. */ + ret = k5_preauth_note_failed(ctx, pa->pa_type); + if (ret) + goto cleanup; + } } } @@ -850,45 +922,54 @@ add_s4u_x509_user_padata(krb5_context context, krb5_s4u_userid *userid, } /* - * If one of the modules can adjust its AS_REQ data using the contents of the - * err_reply, return 0. If it's the sort of correction which requires that we - * ask the user another question, we let the calling application deal with it. + * If the module for pa_type can adjust its AS_REQ data using the contents of + * err and err_padata, return 0 with *padata_out set to a padata list for the + * next request. If it's the sort of correction which requires that we ask the + * user another question, we let the calling application deal with it. */ krb5_error_code k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx, - krb5_pa_data **in_padata, krb5_pa_data ***padata_out) + krb5_preauthtype pa_type, krb5_error *err, + krb5_pa_data **err_padata, krb5_pa_data ***padata_out) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data **mod_pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; - int i; + int count; *padata_out = NULL; - if (pctx == NULL) - return KRB5KRB_ERR_GENERIC; - TRACE_PREAUTH_TRYAGAIN_INPUT(context, in_padata); + TRACE_PREAUTH_TRYAGAIN_INPUT(context, pa_type, err_padata); - for (i = 0; in_padata[i] != NULL; i++) { - h = find_module(pctx->handles, in_padata[i]->pa_type); - if (h == NULL) - continue; - mod_pa = NULL; - ret = clpreauth_tryagain(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, ctx->request, - ctx->inner_request_body, - ctx->encoded_previous_request, - in_padata[i]->pa_type, - ctx->err_reply, ctx->err_padata, - ctx->prompter, ctx->prompter_data, &mod_pa); - if (ret == 0 && mod_pa != NULL) { - TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); - *padata_out = mod_pa; - return 0; - } + h = find_module(context, ctx, pa_type, &modreq); + if (h == NULL) + return KRB5KRB_ERR_GENERIC; + mod_pa = NULL; + ret = clpreauth_tryagain(context, h, modreq, ctx->opt, &callbacks, + (krb5_clpreauth_rock)ctx, ctx->request, + ctx->inner_request_body, + ctx->encoded_previous_request, pa_type, err, + err_padata, ctx->prompter, ctx->prompter_data, + &mod_pa); + TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret); + if (!ret && mod_pa == NULL) + ret = KRB5KRB_ERR_GENERIC; + if (ret) { + k5_preauth_note_failed(ctx, pa_type); + return ret; } - return KRB5KRB_ERR_GENERIC; + + for (count = 0; mod_pa[count] != NULL; count++); + ret = copy_cookie(context, err_padata, &mod_pa, &count); + if (ret) { + krb5_free_pa_data(context, mod_pa); + return ret; + } + + TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa); + *padata_out = mod_pa; + return 0; } /* Compile the set of response items for in_padata by invoke each module's @@ -897,9 +978,9 @@ static krb5_error_code fill_response_items(krb5_context context, krb5_init_creds_context ctx, krb5_pa_data **in_padata) { - struct krb5_preauth_context_st *pctx = context->preauth_context; krb5_error_code ret; krb5_pa_data *pa; + krb5_clpreauth_modreq modreq; clpreauth_handle h; int i; @@ -908,11 +989,11 @@ fill_response_items(krb5_context context, krb5_init_creds_context ctx, pa = in_padata[i]; if (!pa_type_allowed(ctx, pa->pa_type)) continue; - h = find_module(pctx->handles, pa->pa_type); + h = find_module(context, ctx, pa->pa_type, &modreq); if (h == NULL) continue; - ret = clpreauth_prep_questions(context, h, ctx->opt, &callbacks, - (krb5_clpreauth_rock)ctx, + ret = clpreauth_prep_questions(context, h, modreq, ctx->opt, + &callbacks, (krb5_clpreauth_rock)ctx, ctx->request, ctx->inner_request_body, ctx->encoded_previous_request, pa); if (ret) @@ -1004,7 +1085,7 @@ krb5_preauth_supply_preauth_data(krb5_context context, krb5_get_init_creds_opt *opt, const char *attr, const char *value) { - struct krb5_preauth_context_st *pctx = context->preauth_context; + krb5_preauth_context pctx = context->preauth_context; clpreauth_handle *hp, h; krb5_error_code ret; diff --git a/src/lib/krb5/krb/preauth_ec.c b/src/lib/krb5/krb/preauth_ec.c index b1978336a063..c1aa9090fb6c 100644 --- a/src/lib/krb5/krb/preauth_ec.c +++ b/src/lib/krb5/krb/preauth_ec.c @@ -58,6 +58,8 @@ ec_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_keyblock *challenge_key = NULL, *armor_key, *as_key; armor_key = cb->fast_armor(context, rock); + if (armor_key == NULL) + return ENOENT; retval = cb->get_as_key(context, rock, &as_key); if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; diff --git a/src/lib/krb5/krb/send_tgs.c b/src/lib/krb5/krb/send_tgs.c index f6fdf68d4725..e43a5cc5b135 100644 --- a/src/lib/krb5/krb/send_tgs.c +++ b/src/lib/krb5/krb/send_tgs.c @@ -28,6 +28,25 @@ #include "int-proto.h" #include "fast.h" +/* Choose a random nonce for an AS or TGS request. */ +krb5_error_code +k5_generate_nonce(krb5_context context, int32_t *out) +{ + krb5_error_code ret; + unsigned char random_buf[4]; + krb5_data random_data = make_data(random_buf, 4); + + *out = 0; + + /* We and Heimdal incorrectly encode nonces as signed, so make sure we use + * a non-negative value to avoid interoperability issues. */ + ret = krb5_c_random_make_octets(context, &random_data); + if (ret) + return ret; + *out = 0x7FFFFFFF & load_32_n(random_buf); + return 0; +} + /* Construct an AP-REQ message for a TGS request. */ static krb5_error_code tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data, @@ -156,10 +175,13 @@ k5_make_tgs_req(krb5_context context, req.till = desired->times.endtime ? desired->times.endtime : tgt->times.endtime; req.rtime = desired->times.renew_till; + ret = k5_generate_nonce(context, &req.nonce); + if (ret) + return ret; + *nonce_out = req.nonce; ret = krb5_timeofday(context, &time_now); if (ret) return ret; - *nonce_out = req.nonce = (krb5_int32)time_now; *timestamp_out = time_now; req.addresses = (krb5_address **)addrs; diff --git a/src/lib/krb5/krb/sendauth.c b/src/lib/krb5/krb/sendauth.c index f7e6777411aa..149e25dd7362 100644 --- a/src/lib/krb5/krb/sendauth.c +++ b/src/lib/krb5/krb/sendauth.c @@ -131,22 +131,21 @@ krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ - char rnd_data[1024]; + struct sockaddr_storage rnd_data; GETPEERNAME_ARG3_TYPE len2; - krb5_data d; - d.length = sizeof (rnd_data); - d.data = rnd_data; - len2 = sizeof (rnd_data); - if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + krb5_data d = make_data(&rnd_data, sizeof(rnd_data)); + + len2 = sizeof(rnd_data); + if (getpeername(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } - len2 = sizeof (rnd_data); - if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, - &len2) == 0) { + len2 = sizeof(rnd_data); + if (getsockname(*(int *)fd, ss2sa(&rnd_data), &len2) == 0) { d.length = len2; - (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); + (void)krb5_c_random_add_entropy( + context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d); } } diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c index 3ab7eacac1c0..f0a2ae20bab5 100644 --- a/src/lib/krb5/krb/str_conv.c +++ b/src/lib/krb5/krb/str_conv.c @@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen) { size_t ret; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; const char *fmt = "%c"; /* This is to get around gcc -Wall warning that the year returned might be two digits */ @@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen struct tm *tmp; size_t i; size_t ndone; - time_t timestamp2 = timestamp; + time_t timestamp2 = ts2tt(timestamp); struct tm tmbuf; static const char * const sftime_format_table[] = { diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py index e021379ab1cf..aed39e3995ab 100755 --- a/src/lib/krb5/krb/t_expire_warn.py +++ b/src/lib/krb5/krb/t_expire_warn.py @@ -39,15 +39,10 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days']) output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0']) if output: fail('Unexpected output for noexpire') -output = realm.run(['./t_expire_warn', 'minutes', 'pass', '0']) -if ' less than one hour on ' not in output: - fail('Expected warning not seen for minutes') -output = realm.run(['./t_expire_warn', 'hours', 'pass', '0']) -if ' hours on ' not in output: - fail('Expected warning not seen for hours') -output = realm.run(['./t_expire_warn', 'days', 'pass', '0']) -if ' days on ' not in output: - fail('Expected warning not seen for days') +realm.run(['./t_expire_warn', 'minutes', 'pass', '0'], + expected_msg=' less than one hour on ') +realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ') +realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ') # Check for expected expire callback behavior. These tests are # carefully agnostic about whether the KDC supports last_req fields, diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c index 60cfb5b15115..74ac14d9ab64 100644 --- a/src/lib/krb5/krb/t_kerb.c +++ b/src/lib/krb5/krb/t_kerb.c @@ -5,16 +5,8 @@ */ #include "autoconf.h" -#include "krb5.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> +#include "k5-int.h" #include <time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> #include "com_err.h" @@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime) com_err("krb5_string_to_timestamp", retval, 0); return; } - t = (time_t) timestamp; + t = ts2tt(timestamp); printf("Parsed time was %s", ctime(&t)); } diff --git a/src/lib/krb5/krb/t_parse_host_string.c b/src/lib/krb5/krb/t_parse_host_string.c index 76dd20f817b0..001b77389555 100644 --- a/src/lib/krb5/krb/t_parse_host_string.c +++ b/src/lib/krb5/krb/t_parse_host_string.c @@ -31,10 +31,7 @@ */ #include "k5-int.h" -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> +#include "k5-cmocka.h" #include <malloc.h> /* Call k5_parse_host_string() and check the result against the expected code, diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c new file mode 100644 index 000000000000..1b469ffc252f --- /dev/null +++ b/src/lib/krb5/krb/t_valid_times.c @@ -0,0 +1,109 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */ +/* + * Copyright (C) 2017 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "int-proto.h" + +#define BOUNDARY (uint32_t)INT32_MIN + +int +main() +{ + krb5_error_code ret; + krb5_context context; + krb5_ticket_times times = { 0, 0, 0, 0 }; + + ret = krb5_init_context(&context); + assert(!ret); + + /* Current time is within authtime and end time. */ + ret = krb5_set_debugging_time(context, 1000, 0); + times.authtime = 500; + times.endtime = 1500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but within clock skew. */ + times.starttime = 1100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = 1400; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after end time, but within clock skew. */ + times.starttime = 500; + times.endtime = 800; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after end time by more than clock skew. */ + times.endtime = 600; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + /* Current time is within starttime and endtime; current time and + * endtime are across y2038 boundary. */ + ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 200; + times.endtime = BOUNDARY + 500; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime, but by less than clock skew. */ + times.starttime = BOUNDARY + 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is before starttime by more than clock skew. */ + times.starttime = BOUNDARY + 250; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_NYV); + + /* Current time is after endtime, but by less than clock skew. */ + ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0); + assert(!ret); + times.starttime = BOUNDARY - 1000; + times.endtime = BOUNDARY - 100; + ret = krb5int_validate_times(context, ×); + assert(!ret); + + /* Current time is after endtime by more than clock skew. */ + times.endtime = BOUNDARY - 300; + ret = krb5int_validate_times(context, ×); + assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); + + return 0; +} diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c index d63122183eff..294761a882c5 100644 --- a/src/lib/krb5/krb/valid_times.c +++ b/src/lib/krb5/krb/valid_times.c @@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times) else starttime = times->authtime; - if (starttime - currenttime > context->clockskew) + if (ts_after(starttime, ts_incr(currenttime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */ - if ((currenttime - times->endtime) > context->clockskew) + if (ts_after(currenttime, ts_incr(times->endtime, context->clockskew))) return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */ return 0; diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c index 9786d63b5cb1..b4878ba3852e 100644 --- a/src/lib/krb5/krb/vfy_increds.c +++ b/src/lib/krb5/krb/vfy_increds.c @@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server, ret = krb5_timeofday(context, &in_creds.times.endtime); if (ret) goto cleanup; - in_creds.times.endtime += 5*60; + in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60); ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); if (ret) goto cleanup; diff --git a/src/lib/krb5/krb/x-deltat.y b/src/lib/krb5/krb/x-deltat.y index f9cc2bb46959..da11b88077aa 100644 --- a/src/lib/krb5/krb/x-deltat.y +++ b/src/lib/krb5/krb/x-deltat.y @@ -44,7 +44,6 @@ #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "k5-int.h" diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in index efa82e22f35e..5d2fcb5be8fa 100644 --- a/src/lib/krb5/os/Makefile.in +++ b/src/lib/krb5/os/Makefile.in @@ -225,7 +225,7 @@ check-unix-locate: t_locate_kdc $(RUN_TEST) ./t_locate_kdc $(LOCREALM); \ else \ echo '*** WARNING: skipped t_locate_kdc test: known DNS name not found'; \ - echo 'Skipped t_locate_kdc test: known DNS name found' >> $(SKIPTESTS); \ + echo 'Skipped t_locate_kdc test: known DNS name not found' >> $(SKIPTESTS); \ fi; \ else \ echo '*** WARNING: skipped t_locate_kdc test: OFFLINE'; \ diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index df63b14faa56..11552ef42c08 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -30,11 +30,14 @@ /* If this trick gets used elsewhere, move it to k5-platform.h. */ #ifndef DESIGNATED_INITIALIZERS -#define DESIGNATED_INITIALIZERS \ - /* ANSI/ISO C 1999 supports this... */ \ - (__STDC_VERSION__ >= 199901L \ - /* ...as does GCC, since version 2.something. */ \ - || (!defined __cplusplus && __GNUC__ >= 3)) +/* ANSI/ISO C 1999 supports this... */ +#if __STDC_VERSION__ >= 199901L \ + /* ...as does GCC, since version 2.something. */ \ + || (!defined __cplusplus && __GNUC__ >= 3) +#define DESIGNATED_INITIALIZERS 1 +#else +#define DESIGNATED_INITIALIZERS 0 +#endif #endif krb5_error_code KRB5_CALLCONV diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c index 871d72183007..f69f2ea4c332 100644 --- a/src/lib/krb5/os/c_ustime.c +++ b/src/lib/krb5/os/c_ustime.c @@ -29,7 +29,10 @@ k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER; -struct time_now { krb5_int32 sec, usec; }; +struct time_now { + krb5_timestamp sec; + krb5_int32 usec; +}; #if defined(_WIN32) @@ -73,7 +76,7 @@ get_time_now(struct time_now *n) static struct time_now last_time; krb5_error_code -krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) +krb5_crypto_us_timeofday(krb5_timestamp *seconds, krb5_int32 *microseconds) { struct time_now now; krb5_error_code err; @@ -102,17 +105,17 @@ krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) putting now.sec in the past. But don't just use '<' because we need to properly handle the case where the administrator intentionally adjusted time backwards. */ - if ((now.sec == last_time.sec-1) || - ((now.sec == last_time.sec) && (now.usec <= last_time.usec))) { + if (now.sec == ts_incr(last_time.sec, -1) || + (now.sec == last_time.sec && !ts_after(last_time.usec, now.usec))) { /* Correct 'now' to be exactly one microsecond later than 'last_time'. Note that _because_ we perform this hack, 'now' may be _earlier_ than 'last_time', even though the system time is monotonically increasing. */ now.sec = last_time.sec; - now.usec = ++last_time.usec; + now.usec = ts_incr(last_time.usec, 1); if (now.usec >= 1000000) { - ++now.sec; + now.sec = ts_incr(now.sec, 1); now.usec = 0; } } diff --git a/src/lib/krb5/os/dnsglue.c b/src/lib/krb5/os/dnsglue.c index 1a259b399eba..e29066d74bc5 100644 --- a/src/lib/krb5/os/dnsglue.c +++ b/src/lib/krb5/os/dnsglue.c @@ -73,7 +73,7 @@ static int initparse(struct krb5int_dns_state *); #if defined(__APPLE__) -/* Use the OS X interfaces dns_open, dns_search, and dns_free. */ +/* Use the macOS interfaces dns_open, dns_search, and dns_free. */ #define DECLARE_HANDLE(h) dns_handle_t h #define INIT_HANDLE(h) ((h = dns_open(NULL)) != NULL) #define SEARCH(h, n, c, t, a, l) dns_search(h, n, c, t, a, l, NULL, NULL) diff --git a/src/lib/krb5/os/dnsglue.h b/src/lib/krb5/os/dnsglue.h index 27147a6cab51..e7844049db72 100644 --- a/src/lib/krb5/os/dnsglue.h +++ b/src/lib/krb5/os/dnsglue.h @@ -33,9 +33,9 @@ * BIND 4 doesn't have the ns_initparse() API, so we need to do some * manual parsing via the HEADER struct. BIND 8 does have * ns_initparse(), but has enums for the various protocol constants - * rather than the BIND 4 macros. BIND 9 (at least on Mac OS X - * Panther) appears to disable res_nsearch() if BIND_8_COMPAT is - * defined (which is necessary to obtain the HEADER struct). + * rather than the BIND 4 macros. BIND 9 (at least on macOS 10.3) + * appears to disable res_nsearch() if BIND_8_COMPAT is defined + * (which is necessary to obtain the HEADER struct). * * We use ns_initparse() if available at all, and never define * BIND_8_COMPAT. If there is no ns_initparse(), we do manual parsing @@ -167,15 +167,16 @@ struct srv_dns_entry { char *host; }; -krb5_error_code krb5int_make_srv_query_realm(const krb5_data *realm, - const char *service, - const char *protocol, - struct srv_dns_entry **answers); +krb5_error_code +krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, + struct srv_dns_entry **answers); + void krb5int_free_srv_dns_data(struct srv_dns_entry *); krb5_error_code -k5_make_uri_query(const krb5_data *realm, const char *service, - struct srv_dns_entry **answers); +k5_make_uri_query(krb5_context context, const krb5_data *realm, + const char *service, struct srv_dns_entry **answers); #endif /* KRB5_DNS_LOOKUP */ #endif /* !defined(KRB5_DNSGLUE_H) */ diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c index 76f5b63a1774..d66a8f99a0af 100644 --- a/src/lib/krb5/os/dnssrv.c +++ b/src/lib/krb5/os/dnssrv.c @@ -104,8 +104,8 @@ place_srv_entry(struct srv_dns_entry **head, struct srv_dns_entry *new) /* Query the URI RR, collecting weight, priority, and target. */ krb5_error_code -k5_make_uri_query(const krb5_data *realm, const char *service, - struct srv_dns_entry **answers) +k5_make_uri_query(krb5_context context, const krb5_data *realm, + const char *service, struct srv_dns_entry **answers) { const unsigned char *p = NULL, *base = NULL; char host[MAXDNAME]; @@ -121,6 +121,8 @@ k5_make_uri_query(const krb5_data *realm, const char *service, if (ret) return 0; + TRACE_DNS_URI_SEND(context, host); + size = krb5int_dns_init(&ds, host, C_IN, T_URI); if (size < 0) goto out; @@ -148,6 +150,7 @@ k5_make_uri_query(const krb5_data *realm, const char *service, goto out; } + TRACE_DNS_URI_ANS(context, uri->host, uri->priority, uri->weight); place_srv_entry(&head, uri); } @@ -165,9 +168,8 @@ out: */ krb5_error_code -krb5int_make_srv_query_realm(const krb5_data *realm, - const char *service, - const char *protocol, +krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, struct srv_dns_entry **answers) { const unsigned char *p = NULL, *base = NULL; @@ -192,9 +194,7 @@ krb5int_make_srv_query_realm(const krb5_data *realm, if (ret) return 0; -#ifdef TEST - fprintf(stderr, "sending DNS SRV query for %s\n", host); -#endif + TRACE_DNS_SRV_SEND(context, host); size = krb5int_dns_init(&ds, host, C_IN, T_SRV); if (size < 0) @@ -239,6 +239,8 @@ krb5int_make_srv_query_realm(const krb5_data *realm, goto out; } + TRACE_DNS_SRV_ANS(context, srv->host, srv->port, srv->priority, + srv->weight); place_srv_entry(&head, srv); } diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c index a8a14f4bb28b..61fb234594e6 100644 --- a/src/lib/krb5/os/expand_path.c +++ b/src/lib/krb5/os/expand_path.c @@ -351,7 +351,7 @@ expand_null(krb5_context context, PTYPE param, const char *postfix, char **ret) return 0; } -static const struct token { +static const struct { const char *tok; PTYPE param; const char *postfix; diff --git a/src/lib/krb5/os/genaddrs.c b/src/lib/krb5/os/genaddrs.c index 5ef7af5a339f..c818fdb6d79d 100644 --- a/src/lib/krb5/os/genaddrs.c +++ b/src/lib/krb5/os/genaddrs.c @@ -79,8 +79,8 @@ krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR)) { - if ((retval = getsockname(fd, (GETSOCKNAME_ARG2_TYPE *) &lsaddr, - &ssize))) + retval = getsockname(fd, ss2sa(&lsaddr), &ssize); + if (retval) return retval; if (cvtaddr (&lsaddr, &laddrs)) { @@ -99,8 +99,8 @@ krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR)) { - if ((retval = getpeername(fd, (GETPEERNAME_ARG2_TYPE *) &rsaddr, - &ssize))) + retval = getpeername(fd, ss2sa(&rsaddr), &ssize); + if (retval) return errno; if (cvtaddr (&rsaddr, &raddrs)) { diff --git a/src/lib/krb5/os/hostaddr.c b/src/lib/krb5/os/hostaddr.c index 22f6ad6d48b9..d7a4a763012d 100644 --- a/src/lib/krb5/os/hostaddr.c +++ b/src/lib/krb5/os/hostaddr.c @@ -83,12 +83,12 @@ k5_os_hostaddr(krb5_context context, const char *name, switch (aip->ai_addr->sa_family) { case AF_INET: addrlen = sizeof (struct in_addr); - ptr = &((struct sockaddr_in *)aip->ai_addr)->sin_addr; + ptr = &sa2sin(aip->ai_addr)->sin_addr; atype = ADDRTYPE_INET; break; case AF_INET6: addrlen = sizeof (struct in6_addr); - ptr = &((struct sockaddr_in6 *)aip->ai_addr)->sin6_addr; + ptr = &sa2sin6(aip->ai_addr)->sin6_addr; atype = ADDRTYPE_INET6; break; default: diff --git a/src/lib/krb5/os/localaddr.c b/src/lib/krb5/os/localaddr.c index 9f7765254467..58443f6e354a 100644 --- a/src/lib/krb5/os/localaddr.c +++ b/src/lib/krb5/os/localaddr.c @@ -181,11 +181,11 @@ is_loopback_address(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: { - struct sockaddr_in *s4 = (struct sockaddr_in *)sa; + struct sockaddr_in *s4 = sa2sin(sa); return s4->sin_addr.s_addr == htonl(INADDR_LOOPBACK); } case AF_INET6: { - struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa; + struct sockaddr_in6 *s6 = sa2sin6(sa); return IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr); } default: @@ -239,16 +239,17 @@ printifaddr(struct ifaddrs *ifp) #include <stdlib.h> static int -addr_eq (const struct sockaddr *s1, const struct sockaddr *s2) +addr_eq (struct sockaddr *s1, struct sockaddr *s2) { if (s1->sa_family != s2->sa_family) return 0; -#define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F))) switch (s1->sa_family) { case AF_INET: - return CMPTYPE (struct sockaddr_in, sin_addr); + return !memcmp(&sa2sin(s1)->sin_addr, &sa2sin(s2)->sin_addr, + sizeof(sa2sin(s1)->sin_addr)); case AF_INET6: - return CMPTYPE (struct sockaddr_in6, sin6_addr); + return !memcmp(&sa2sin6(s1)->sin6_addr, &sa2sin6(s2)->sin6_addr, + sizeof(sa2sin6(s1)->sin6_addr)); default: /* Err on side of duplicate listings. */ return 0; @@ -861,6 +862,9 @@ get_ifreq_array(char **bufp, size_t *np, int s) int numifs = -1; #endif + *bufp = NULL; + *np = 0; + /* At least on NetBSD, an ifreq can hold an IPv4 address, but isn't big enough for an IPv6 or ethernet address. So add a little more space. */ @@ -937,9 +941,9 @@ foreach_localaddr (/*@null@*/ void *data, #endif { struct ifreq *ifr, ifreq, *ifr2; - int s, code; + int s; char *buf = 0; - size_t size, n, i, j; + size_t n, i, j; int retval = 0; #ifdef LINUX_IPV6_HACK struct linux_ipv6_addr_list *linux_ipv6_addrs = get_linux_ipv6_addrs (); @@ -1183,14 +1187,14 @@ add_addr (void *P_data, struct sockaddr *a) #ifdef HAVE_NETINET_IN_H case AF_INET: address = make_addr (ADDRTYPE_INET, sizeof (struct in_addr), - &((const struct sockaddr_in *) a)->sin_addr); + &sa2sin(a)->sin_addr); if (address == NULL) data->mem_err++; break; case AF_INET6: { - const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) a; + const struct sockaddr_in6 *in = sa2sin6(a); if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr)) break; diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c index 014ec6ecb902..b9edecc7a910 100644 --- a/src/lib/krb5/os/locate_kdc.c +++ b/src/lib/krb5/os/locate_kdc.c @@ -313,14 +313,16 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm, #ifdef KRB5_DNS_LOOKUP static krb5_error_code -locate_srv_dns_1(const krb5_data *realm, const char *service, - const char *protocol, struct serverlist *serverlist) +locate_srv_dns_1(krb5_context context, const krb5_data *realm, + const char *service, const char *protocol, + struct serverlist *serverlist) { struct srv_dns_entry *head = NULL, *entry = NULL; krb5_error_code code = 0; k5_transport transport; - code = krb5int_make_srv_query_realm(realm, service, protocol, &head); + code = krb5int_make_srv_query_realm(context, realm, service, protocol, + &head); if (code) return 0; @@ -598,9 +600,10 @@ parse_uri_fields(const char *uri, k5_transport *transport_out, * and transport type. Problematic entries are skipped. */ static krb5_error_code -locate_uri(const krb5_data *realm, const char *req_service, - struct serverlist *serverlist, k5_transport req_transport, - int default_port, krb5_boolean master_only) +locate_uri(krb5_context context, const krb5_data *realm, + const char *req_service, struct serverlist *serverlist, + k5_transport req_transport, int default_port, + krb5_boolean master_only) { krb5_error_code ret; k5_transport transport, host_trans; @@ -609,7 +612,7 @@ locate_uri(const krb5_data *realm, const char *req_service, const char *host_field, *path; int port, def_port, master; - ret = k5_make_uri_query(realm, req_service, &answers); + ret = k5_make_uri_query(context, realm, req_service, &answers); if (ret || answers == NULL) return ret; @@ -688,10 +691,11 @@ dns_locate_server_uri(krb5_context context, const krb5_data *realm, return 0; } - ret = locate_uri(realm, svcname, serverlist, transport, def_port, + ret = locate_uri(context, realm, svcname, serverlist, transport, def_port, find_master); - if (ret) - Tprintf("dns URI lookup returned error %d\n", ret); + + if (serverlist->nservers == 0) + TRACE_DNS_URI_NOTFOUND(context); return ret; } @@ -729,16 +733,15 @@ dns_locate_server_srv(krb5_context context, const krb5_data *realm, } code = 0; - if (transport == UDP || transport == TCP_OR_UDP) { - code = locate_srv_dns_1(realm, dnsname, "_udp", serverlist); - if (code) - Tprintf("dns udp lookup returned error %d\n", code); - } - if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) { - code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist); - if (code) - Tprintf("dns tcp lookup returned error %d\n", code); - } + if (transport == UDP || transport == TCP_OR_UDP) + code = locate_srv_dns_1(context, realm, dnsname, "_udp", serverlist); + + if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) + code = locate_srv_dns_1(context, realm, dnsname, "_tcp", serverlist); + + if (serverlist->nservers == 0) + TRACE_DNS_SRV_NOTFOUND(context); + return code; } #endif /* KRB5_DNS_LOOKUP */ diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index fffe0262f6bb..e8bc0ad6e2f5 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -253,7 +253,7 @@ cm_get_ssflags(struct select_state *selstate, int fd) struct pollfd *pfd = find_pollfd(selstate, fd); /* - * OS X sets POLLHUP without POLLOUT on connection error. Catch this as + * macOS sets POLLHUP without POLLOUT on connection error. Catch this as * well as other error events such as POLLNVAL, but only if POLLIN and * POLLOUT aren't set, as we can get POLLHUP along with POLLIN with TCP * data still to be read. @@ -1372,8 +1372,7 @@ get_endtime(time_ms endtime, struct conn_state *conns) struct conn_state *state; for (state = conns; state != NULL; state = state->next) { - if (state->addr.transport == TCP && - (state->state == READING || state->state == WRITING) && + if ((state->state == READING || state->state == WRITING) && state->endtime > endtime) endtime = state->endtime; } diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c index 6414b8e92d79..7a53c842a80e 100644 --- a/src/lib/krb5/os/t_locate_kdc.c +++ b/src/lib/krb5/os/t_locate_kdc.c @@ -127,7 +127,7 @@ main (int argc, char *argv[]) break; case LOOKUP_DNS: - err = locate_srv_dns_1(&realm, "_kerberos", "_udp", &sl); + err = locate_srv_dns_1(ctx, &realm, "_kerberos", "_udp", &sl); break; case LOOKUP_WHATEVER: diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c index fddb1214296f..d4e36b1c7572 100644 --- a/src/lib/krb5/os/timeofday.c +++ b/src/lib/krb5/os/timeofday.c @@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date) retval = krb5_timeofday(context, ¤ttime); if (retval) return retval; - if (!(labs((date)-currenttime) < context->clockskew)) + if (!ts_within(date, currenttime, context->clockskew)) return KRB5KRB_AP_ERR_SKEW; return 0; diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c index 456193a41aed..4bbcdde52812 100644 --- a/src/lib/krb5/os/toffset.c +++ b/src/lib/krb5/os/toffset.c @@ -40,14 +40,15 @@ krb5_error_code KRB5_CALLCONV krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds) { krb5_os_context os_ctx = &context->os_context; - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; krb5_error_code retval; retval = krb5_crypto_us_timeofday(&sec, &usec); if (retval) return retval; - os_ctx->time_offset = seconds - sec; + os_ctx->time_offset = ts_delta(seconds, sec); os_ctx->usec_offset = (microseconds > -1) ? microseconds - usec : 0; os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) | diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c index 83c8d4db876a..e97ce5fe5d66 100644 --- a/src/lib/krb5/os/trace.c +++ b/src/lib/krb5/os/trace.c @@ -173,7 +173,7 @@ trace_format(krb5_context context, const char *fmt, va_list ap) p = va_arg(ap, const char *); if (p == NULL && len != 0) k5_buf_add(&buf, "(null)"); - else + else if (p != NULL) buf_add_printable_len(&buf, p, len); } else if (strcmp(tmpbuf, "hexlenstr") == 0) { len = va_arg(ap, size_t); @@ -340,7 +340,8 @@ krb5int_trace(krb5_context context, const char *fmt, ...) va_list ap; krb5_trace_info info; char *str = NULL, *msg = NULL; - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; if (context == NULL || context->trace_callback == NULL) return; @@ -350,7 +351,7 @@ krb5int_trace(krb5_context context, const char *fmt, ...) goto cleanup; if (krb5_crypto_us_timeofday(&sec, &usec) != 0) goto cleanup; - if (asprintf(&msg, "[%d] %d.%d: %s\n", (int) getpid(), (int) sec, + if (asprintf(&msg, "[%d] %u.%d: %s\n", (int) getpid(), (unsigned int) sec, (int) usec, str) < 0) goto cleanup; info.message = msg; diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c index 056357683456..a80fdf68ca48 100644 --- a/src/lib/krb5/os/ustime.c +++ b/src/lib/krb5/os/ustime.c @@ -40,7 +40,8 @@ krb5_error_code k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, krb5_timestamp *time_out, krb5_int32 *usec_out) { - krb5_int32 sec, usec; + krb5_timestamp sec; + krb5_int32 usec; krb5_error_code retval; retval = krb5_crypto_us_timeofday(&sec, &usec); @@ -49,13 +50,13 @@ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, usec += offset_usec; if (usec > 1000000) { usec -= 1000000; - sec++; + sec = ts_incr(sec, 1); } if (usec < 0) { usec += 1000000; - sec--; + sec = ts_incr(sec, -1); } - sec += offset; + sec = ts_incr(sec, offset); *time_out = sec; *usec_out = usec; diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c index c4d2c744da40..1e0cb22c94e2 100644 --- a/src/lib/krb5/rcache/rc_dfl.c +++ b/src/lib/krb5/rcache/rc_dfl.c @@ -93,12 +93,11 @@ cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t) } static int -alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t) +alive(krb5_timestamp mytime, krb5_donot_replay *new1, krb5_deltat t) { if (mytime == 0) return CMP_HOHUM; /* who cares? */ - /* I hope we don't have to worry about overflow */ - if (new1->ctime + t < mytime) + if (ts_after(mytime, ts_incr(new1->ctime, t))) return CMP_EXPIRED; return CMP_HOHUM; } @@ -130,7 +129,7 @@ struct authlist static int rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep, - krb5_int32 now, krb5_boolean fromfile) + krb5_timestamp now, krb5_boolean fromfile) { struct dfl_data *t = (struct dfl_data *)id->data; unsigned int rephash; @@ -517,7 +516,7 @@ errout: free(rep->server); if (rep->msghash) free(rep->msghash); - rep->client = rep->server = 0; + rep->client = rep->server = rep->msghash = NULL; return retval; } @@ -537,7 +536,7 @@ krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id) krb5_error_code retval; long max_size; int expired_entries = 0; - krb5_int32 now; + krb5_timestamp now; if ((retval = krb5_rc_io_open(context, &t->d, t->name))) { return retval; @@ -707,7 +706,7 @@ krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep) { krb5_error_code ret; struct dfl_data *t; - krb5_int32 now; + krb5_timestamp now; ret = krb5_timeofday(context, &now); if (ret) @@ -763,7 +762,7 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id) struct authlist **qt; struct authlist *r; struct authlist *rt; - krb5_int32 now; + krb5_timestamp now; if (krb5_timestamp(context, &now)) now = 0; diff --git a/src/lib/krb5/rcache/ser_rc.c b/src/lib/krb5/rcache/ser_rc.c index 556af21e5e48..5c537f08a1cc 100644 --- a/src/lib/krb5/rcache/ser_rc.c +++ b/src/lib/krb5/rcache/ser_rc.c @@ -72,7 +72,7 @@ krb5_rcache_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) * krb5_int32 for KV5M_RCACHE */ required = sizeof(krb5_int32) * 3; - if (rcache->ops && rcache->ops->type) + if (rcache->ops) required += (strlen(rcache->ops->type)+1); /* diff --git a/src/lib/krb5/rcache/t_replay.c b/src/lib/krb5/rcache/t_replay.c index db273ec2f221..b99cdf1abb8e 100644 --- a/src/lib/krb5/rcache/t_replay.c +++ b/src/lib/krb5/rcache/t_replay.c @@ -110,7 +110,7 @@ store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg, krb5_donot_replay rep; krb5_data d; - if (now_timestamp > 0) + if (now_timestamp != 0) krb5_set_debugging_time(ctx, now_timestamp, now_usec); if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec))) goto cleanup; @@ -221,13 +221,13 @@ main(int argc, char **argv) msg = (**argv) ? *argv : NULL; argc--; argv++; if (!argc) usage(progname); - timestamp = (krb5_timestamp) atol(*argv); + timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); usec = (krb5_int32) atol(*argv); argc--; argv++; if (!argc) usage(progname); - now_timestamp = (krb5_timestamp) atol(*argv); + now_timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); now_usec = (krb5_int32) atol(*argv); @@ -249,7 +249,7 @@ main(int argc, char **argv) rcspec = *argv; argc--; argv++; if (!argc) usage(progname); - now_timestamp = (krb5_timestamp) atol(*argv); + now_timestamp = (krb5_timestamp) atoll(*argv); argc--; argv++; if (!argc) usage(progname); now_usec = (krb5_int32) atol(*argv); diff --git a/src/lib/krb5/unicode/ure/ure.c b/src/lib/krb5/unicode/ure/ure.c index d1cfd8af945e..23a03d94ffa2 100644 --- a/src/lib/krb5/unicode/ure/ure.c +++ b/src/lib/krb5/unicode/ure/ure.c @@ -421,7 +421,7 @@ _ure_prop_list(ucs2_t *pp, unsigned long limit, unsigned long *mask, b->error = _URE_INVALID_PROPERTY; } - if (n != 0) + if (b->error == _URE_OK && n != 0) m |= cclass_flags[n]; /* diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def index e5b560dfcb26..f7b428e16928 100644 --- a/src/lib/krb5_32.def +++ b/src/lib/krb5_32.def @@ -470,3 +470,6 @@ EXPORTS krb5_get_init_creds_opt_set_pac_request @435 krb5int_trace @436 ; PRIVATE GSSAPI krb5_expand_hostname @437 + +; new in 1.16 + k5_enctype_to_ssf @438 ; PRIVATE GSSAPI diff --git a/src/lib/rpc/deps b/src/lib/rpc/deps index 3c5af2f795bd..f57b831d9c65 100644 --- a/src/lib/rpc/deps +++ b/src/lib/rpc/deps @@ -180,7 +180,8 @@ pmap_rmt.so pmap_rmt.po $(OUTPRE)pmap_rmt.$(OBJEXT): \ $(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-platform.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/port-sockets.h pmap_rmt.c + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + pmap_rmt.c rpc_prot.so rpc_prot.po $(OUTPRE)rpc_prot.$(OBJEXT): \ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \ $(top_srcdir)/include/gssrpc/auth.h $(top_srcdir)/include/gssrpc/auth_gss.h \ diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c index cd0b3095ae4f..4829e3ff06c3 100644 --- a/src/lib/rpc/pmap_rmt.c +++ b/src/lib/rpc/pmap_rmt.c @@ -60,6 +60,7 @@ static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; #include <arpa/inet.h> #define MAX_BROADCAST_SIZE 1400 #include <port-sockets.h> +#include "socket-utils.h" static struct timeval timeout = { 3, 0 }; @@ -208,12 +209,11 @@ getbroadcastnets( if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { addrs[i++].s_addr = INADDR_ANY; } else { - addrs[i++] = ((struct sockaddr_in*) - &ifreq.ifr_addr)->sin_addr; + addrs[i++] = sa2sin(&ifreq.ifr_addr)->sin_addr; } #else /* 4.2 BSD */ struct sockaddr_in *sockin; - sockin = (struct sockaddr_in *)&ifr->ifr_addr; + sockin = sa2sin(&ifr->ifr_addr); addrs[i++] = inet_makeaddr(inet_netof (sockin->sin_addr.s_addr), INADDR_ANY); #endif |