static krb5_socket_t make_signal_socket (krb5_context context) { #ifndef NO_UNIX_SOCKETS struct sockaddr_un addr; const char *fn; krb5_socket_t fd; fn = kadm5_log_signal_socket(context); fd = socket (AF_UNIX, SOCK_DGRAM, 0); if (fd < 0) krb5_err (context, 1, errno, "socket AF_UNIX"); memset (&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strlcpy (addr.sun_path, fn, sizeof(addr.sun_path)); unlink (addr.sun_path); if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) krb5_err (context, 1, errno, "bind %s", addr.sun_path); return fd; #else struct addrinfo *ai = NULL; krb5_socket_t fd; kadm5_log_signal_socket_info(context, 1, &ai); fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (rk_IS_BAD_SOCKET(fd)) krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF=%d", ai->ai_family); if (rk_IS_SOCKET_ERROR( bind (fd, ai->ai_addr, ai->ai_addrlen) )) krb5_err (context, 1, rk_SOCK_ERRNO, "bind"); return fd; #endif }
static void socket_free(krb5_storage * sp) { int save_errno = errno; if (rk_IS_SOCKET_ERROR(rk_closesocket(SOCK(sp)))) errno = rk_SOCK_ERRNO; else errno = save_errno; }
static void wait_for_connection(krb5_context context, krb5_socket_t *socks, unsigned int num_socks) { unsigned int i; int e; fd_set orig_read_set, read_set; int status, max_fd = -1; FD_ZERO(&orig_read_set); for(i = 0; i < num_socks; i++) { #ifdef FD_SETSIZE if (socks[i] >= FD_SETSIZE) errx (1, "fd too large"); #endif FD_SET(socks[i], &orig_read_set); max_fd = max(max_fd, socks[i]); } pgrp = getpid(); if(setpgid(0, pgrp) < 0) err(1, "setpgid"); signal(SIGTERM, terminate); signal(SIGINT, terminate); signal(SIGCHLD, sigchld); while (term_flag == 0) { read_set = orig_read_set; e = select(max_fd + 1, &read_set, NULL, NULL, NULL); if(rk_IS_SOCKET_ERROR(e)) { if(rk_SOCK_ERRNO != EINTR) krb5_warn(context, rk_SOCK_ERRNO, "select"); } else if(e == 0) krb5_warnx(context, "select returned 0"); else { for(i = 0; i < num_socks; i++) { if(FD_ISSET(socks[i], &read_set)) if(spawn_child(context, socks, num_socks, i) == 0) return; } } } signal(SIGCHLD, SIG_IGN); while ((waitpid(-1, &status, WNOHANG)) > 0) ; exit(0); }
ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL net_read(rk_socket_t sock, void *buf, size_t nbytes) { char *cbuf = (char *)buf; ssize_t count; size_t rem = nbytes; #ifdef SOCKET_IS_NOT_AN_FD int use_read = 0; #endif while (rem > 0) { #ifdef SOCKET_IS_NOT_AN_FD if (use_read) count = _read (sock, cbuf, rem); else count = recv (sock, cbuf, rem, 0); if (use_read == 0 && rk_IS_SOCKET_ERROR(count) && (rk_SOCK_ERRNO == WSANOTINITIALISED || rk_SOCK_ERRNO == WSAENOTSOCK)) { use_read = 1; count = _read (sock, cbuf, rem); } #else count = recv (sock, cbuf, rem, 0); #endif if (count < 0) { /* With WinSock, the error EINTR (WSAEINTR), is used to indicate that a blocking call was cancelled using WSACancelBlockingCall(). */ #ifndef HAVE_WINSOCK if (rk_SOCK_ERRNO == EINTR) continue; #endif return count; } else if (count == 0) { return count; } cbuf += count; rem -= count; } return nbytes; }
void start_server(krb5_context context, const char *port_str) { int e; struct kadm_port *p; krb5_socket_t *socks = NULL, *tmp; unsigned int num_socks = 0; int i; if (port_str == NULL) port_str = "+"; parse_ports(context, port_str); for(p = kadm_ports; p; p = p->next) { struct addrinfo hints, *ai, *ap; char portstr[32]; memset (&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; e = getaddrinfo(NULL, p->port, &hints, &ai); if(e) { snprintf(portstr, sizeof(portstr), "%u", p->def_port); e = getaddrinfo(NULL, portstr, &hints, &ai); } if(e) { krb5_warn(context, krb5_eai_to_heim_errno(e, errno), "%s", portstr); continue; } i = 0; for(ap = ai; ap; ap = ap->ai_next) i++; tmp = realloc(socks, (num_socks + i) * sizeof(*socks)); if(tmp == NULL) { krb5_warnx(context, "failed to reallocate %lu bytes", (unsigned long)(num_socks + i) * sizeof(*socks)); continue; } socks = tmp; for(ap = ai; ap; ap = ap->ai_next) { krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); if(rk_IS_BAD_SOCKET(s)) { krb5_warn(context, rk_SOCK_ERRNO, "socket"); continue; } socket_set_reuseaddr(s, 1); socket_set_ipv6only(s, 1); if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) { krb5_warn(context, rk_SOCK_ERRNO, "bind"); rk_closesocket(s); continue; } if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) { krb5_warn(context, rk_SOCK_ERRNO, "listen"); rk_closesocket(s); continue; } socks[num_socks++] = s; } freeaddrinfo (ai); } if(num_socks == 0) krb5_errx(context, 1, "no sockets to listen to - exiting"); wait_for_connection(context, socks, num_socks); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, krb5_socket_t fd, int flags) { krb5_error_code ret; krb5_address local_k_address, remote_k_address; krb5_address *lptr = NULL, *rptr = NULL; struct sockaddr_storage ss_local, ss_remote; struct sockaddr *local = (struct sockaddr *)&ss_local; struct sockaddr *remote = (struct sockaddr *)&ss_remote; socklen_t len; if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR) { if (auth_context->local_address == NULL) { len = sizeof(ss_local); if(rk_IS_SOCKET_ERROR(getsockname(fd, local, &len))) { char buf[128]; ret = rk_SOCK_ERRNO; rk_strerror_r(ret, buf, sizeof(buf)); krb5_set_error_message(context, ret, "getsockname: %s", buf); goto out; } ret = krb5_sockaddr2address (context, local, &local_k_address); if(ret) goto out; if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) { krb5_sockaddr2port (context, local, &auth_context->local_port); } else auth_context->local_port = 0; lptr = &local_k_address; } } if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR) { len = sizeof(ss_remote); if(rk_IS_SOCKET_ERROR(getpeername(fd, remote, &len))) { char buf[128]; ret = rk_SOCK_ERRNO; rk_strerror_r(ret, buf, sizeof(buf)); krb5_set_error_message(context, ret, "getpeername: %s", buf); goto out; } ret = krb5_sockaddr2address (context, remote, &remote_k_address); if(ret) goto out; if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) { krb5_sockaddr2port (context, remote, &auth_context->remote_port); } else auth_context->remote_port = 0; rptr = &remote_k_address; } ret = krb5_auth_con_setaddrs (context, auth_context, lptr, rptr); out: if (lptr) krb5_free_address (context, lptr); if (rptr) krb5_free_address (context, rptr); return ret; }
KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL krb5_net_write_block(krb5_context context, void *p_fd, const void *buf, size_t len, time_t timeout) { krb5_socket_t fd = *((krb5_socket_t *)p_fd); int ret; struct timeval tv, *tvp; const char *cbuf = (const char *)buf; size_t rem = len; ssize_t count; fd_set wfds; do { FD_ZERO(&wfds); FD_SET(fd, &wfds); if (timeout != 0) { tv.tv_sec = timeout; tv.tv_usec = 0; tvp = &tv; } else tvp = NULL; ret = select(fd + 1, NULL, &wfds, NULL, tvp); if (rk_IS_SOCKET_ERROR(ret)) { if (rk_SOCK_ERRNO == EINTR) continue; return -1; } #ifdef HAVE_WINSOCK if (ret == 0) { WSASetLastError( WSAETIMEDOUT ); return 0; } count = send (fd, cbuf, rem, 0); if (rk_IS_SOCKET_ERROR(count)) { return -1; } #else if (ret == 0) { return 0; } if (!FD_ISSET(fd, &wfds)) { errno = ETIMEDOUT; return -1; } count = write (fd, cbuf, rem); if (count < 0) { if (errno == EINTR) continue; else return count; } #endif cbuf += count; rem -= count; } while (rem > 0); return len; }