diff options
Diffstat (limited to 'crypto/heimdal/kcm/connect.c')
-rw-r--r-- | crypto/heimdal/kcm/connect.c | 688 |
1 files changed, 0 insertions, 688 deletions
diff --git a/crypto/heimdal/kcm/connect.c b/crypto/heimdal/kcm/connect.c deleted file mode 100644 index b3a21aa..0000000 --- a/crypto/heimdal/kcm/connect.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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 "kcm_locl.h" - -RCSID("$Id: connect.c 16314 2005-11-29 19:03:50Z lha $"); - -struct descr { - int s; - int type; - char *path; - unsigned char *buf; - size_t size; - size_t len; - time_t timeout; - struct sockaddr_storage __ss; - struct sockaddr *sa; - socklen_t sock_len; - kcm_client peercred; -}; - -static void -init_descr(struct descr *d) -{ - memset(d, 0, sizeof(*d)); - d->sa = (struct sockaddr *)&d->__ss; - d->s = -1; -} - -/* - * re-initialize all `n' ->sa in `d'. - */ - -static void -reinit_descrs (struct descr *d, int n) -{ - int i; - - for (i = 0; i < n; ++i) - d[i].sa = (struct sockaddr *)&d[i].__ss; -} - -/* - * Update peer credentials from socket. - * - * SCM_CREDS can only be updated the first time there is read data to - * read from the filedescriptor, so if we read do it before this - * point, the cred data might not be is not there yet. - */ - -static int -update_client_creds(int s, kcm_client *peer) -{ -#ifdef GETPEERUCRED - /* Solaris 10 */ - { - ucred_t *peercred; - - if (getpeerucred(s, &peercred) != 0) { - peer->uid = ucred_geteuid(peercred); - peer->gid = ucred_getegid(peercred); - peer->pid = 0; - ucred_free(peercred); - return 0; - } - } -#endif -#ifdef GETPEEREID - /* FreeBSD, OpenBSD */ - { - uid_t uid; - gid_t gid; - - if (getpeereid(s, &uid, &gid) == 0) { - peer->uid = uid; - peer->gid = gid; - peer->pid = 0; - return 0; - } - } -#endif -#ifdef SO_PEERCRED - /* Linux */ - { - struct ucred pc; - socklen_t pclen = sizeof(pc); - - if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) { - peer->uid = pc.uid; - peer->gid = pc.gid; - peer->pid = pc.pid; - return 0; - } - } -#endif -#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION) - { - struct xucred peercred; - socklen_t peercredlen = sizeof(peercred); - - if (getsockopt(s, LOCAL_PEERCRED, 1, - (void *)&peercred, &peercredlen) == 0 - && peercred.cr_version == XUCRED_VERSION) - { - peer->uid = peercred.cr_uid; - peer->gid = peercred.cr_gid; - peer->pid = 0; - return 0; - } - } -#endif -#if defined(SOCKCREDSIZE) && defined(SCM_CREDS) - /* NetBSD */ - if (peer->uid == -1) { - struct msghdr msg; - socklen_t crmsgsize; - void *crmsg; - struct cmsghdr *cmp; - struct sockcred *sc; - - memset(&msg, 0, sizeof(msg)); - crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS)); - if (crmsgsize == 0) - return 1 ; - - crmsg = malloc(crmsgsize); - if (crmsg == NULL) - goto failed_scm_creds; - - memset(crmsg, 0, crmsgsize); - - msg.msg_control = crmsg; - msg.msg_controllen = crmsgsize; - - if (recvmsg(s, &msg, 0) < 0) { - free(crmsg); - goto failed_scm_creds; - } - - if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { - free(crmsg); - goto failed_scm_creds; - } - - cmp = CMSG_FIRSTHDR(&msg); - if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) { - free(crmsg); - goto failed_scm_creds; - } - - sc = (struct sockcred *)(void *)CMSG_DATA(cmp); - - peer->uid = sc->sc_euid; - peer->gid = sc->sc_egid; - peer->pid = 0; - - free(crmsg); - return 0; - } else { - /* we already got the cred, just return it */ - return 0; - } - failed_scm_creds: -#endif - krb5_warn(kcm_context, errno, "failed to determine peer identity"); - return 1; -} - - -/* - * Create the socket (family, type, port) in `d' - */ - -static void -init_socket(struct descr *d) -{ - struct sockaddr_un un; - struct sockaddr *sa = (struct sockaddr *)&un; - krb5_socklen_t sa_size = sizeof(un); - - init_descr (d); - - un.sun_family = AF_UNIX; - - if (socket_path != NULL) - d->path = socket_path; - else - d->path = _PATH_KCM_SOCKET; - - strlcpy(un.sun_path, d->path, sizeof(un.sun_path)); - - d->s = socket(AF_UNIX, SOCK_STREAM, 0); - if (d->s < 0){ - krb5_warn(kcm_context, errno, "socket(%d, %d, 0)", AF_UNIX, SOCK_STREAM); - d->s = -1; - return; - } -#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) - { - int one = 1; - setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); - } -#endif -#ifdef LOCAL_CREDS - { - int one = 1; - setsockopt(d->s, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); - } -#endif - - d->type = SOCK_STREAM; - - unlink(d->path); - - if (bind(d->s, sa, sa_size) < 0) { - krb5_warn(kcm_context, errno, "bind %s", un.sun_path); - close(d->s); - d->s = -1; - return; - } - - if (listen(d->s, SOMAXCONN) < 0) { - krb5_warn(kcm_context, errno, "listen %s", un.sun_path); - close(d->s); - d->s = -1; - return; - } - - chmod(d->path, 0777); - - return; -} - -/* - * Allocate descriptors for all the sockets that we should listen on - * and return the number of them. - */ - -static int -init_sockets(struct descr **desc) -{ - struct descr *d; - size_t num = 0; - - d = (struct descr *)malloc(sizeof(*d)); - if (d == NULL) { - krb5_errx(kcm_context, 1, "malloc failed"); - } - - init_socket(d); - if (d->s != -1) { - kcm_log(5, "listening on domain socket %s", d->path); - num++; - } - - reinit_descrs (d, num); - *desc = d; - - return num; -} - -/* - * handle the request in `buf, len', from `addr' (or `from' as a string), - * sending a reply in `reply'. - */ - -static int -process_request(unsigned char *buf, - size_t len, - krb5_data *reply, - kcm_client *client) -{ - krb5_data request; - - if (len < 4) { - kcm_log(1, "malformed request from process %d (too short)", - client->pid); - return -1; - } - - if (buf[0] != KCM_PROTOCOL_VERSION_MAJOR || - buf[1] != KCM_PROTOCOL_VERSION_MINOR) { - kcm_log(1, "incorrect protocol version %d.%d from process %d", - buf[0], buf[1], client->pid); - return -1; - } - - buf += 2; - len -= 2; - - /* buf is now pointing at opcode */ - - request.data = buf; - request.length = len; - - return kcm_dispatch(kcm_context, client, &request, reply); -} - -/* - * Handle the request in `buf, len' to socket `d' - */ - -static void -do_request(void *buf, size_t len, struct descr *d) -{ - krb5_error_code ret; - krb5_data reply; - - reply.length = 0; - - ret = process_request(buf, len, &reply, &d->peercred); - if (reply.length != 0) { - unsigned char len[4]; - struct msghdr msghdr; - struct iovec iov[2]; - - kcm_log(5, "sending %lu bytes to process %d", - (unsigned long)reply.length, - (int)d->peercred.pid); - - memset (&msghdr, 0, sizeof(msghdr)); - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = iov; - msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); -#if 0 - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; -#endif - - len[0] = (reply.length >> 24) & 0xff; - len[1] = (reply.length >> 16) & 0xff; - len[2] = (reply.length >> 8) & 0xff; - len[3] = reply.length & 0xff; - - iov[0].iov_base = (void*)len; - iov[0].iov_len = 4; - iov[1].iov_base = reply.data; - iov[1].iov_len = reply.length; - - if (sendmsg (d->s, &msghdr, 0) < 0) { - kcm_log (0, "sendmsg(%d): %d %s", (int)d->peercred.pid, - errno, strerror(errno)); - krb5_data_free(&reply); - return; - } - - krb5_data_free(&reply); - } - - if (ret) { - kcm_log(0, "Failed processing %lu byte request from process %d", - (unsigned long)len, d->peercred.pid); - } -} - -static void -clear_descr(struct descr *d) -{ - if(d->buf) - memset(d->buf, 0, d->size); - d->len = 0; - if(d->s != -1) - close(d->s); - d->s = -1; -} - -#define STREAM_TIMEOUT 4 - -/* - * accept a new stream connection on `d[parent]' and store it in `d[child]' - */ - -static void -add_new_stream (struct descr *d, int parent, int child) -{ - int s; - - if (child == -1) - return; - - d[child].peercred.pid = -1; - d[child].peercred.uid = -1; - d[child].peercred.gid = -1; - - d[child].sock_len = sizeof(d[child].__ss); - s = accept(d[parent].s, d[child].sa, &d[child].sock_len); - if(s < 0) { - krb5_warn(kcm_context, errno, "accept"); - return; - } - - if (s >= FD_SETSIZE) { - krb5_warnx(kcm_context, "socket FD too large"); - close (s); - return; - } - - d[child].s = s; - d[child].timeout = time(NULL) + STREAM_TIMEOUT; - d[child].type = SOCK_STREAM; -} - -/* - * Grow `d' to handle at least `n'. - * Return != 0 if fails - */ - -static int -grow_descr (struct descr *d, size_t n) -{ - if (d->size - d->len < n) { - unsigned char *tmp; - size_t grow; - - grow = max(1024, d->len + n); - if (d->size + grow > max_request) { - kcm_log(0, "Request exceeds max request size (%lu bytes).", - (unsigned long)d->size + grow); - clear_descr(d); - return -1; - } - tmp = realloc (d->buf, d->size + grow); - if (tmp == NULL) { - kcm_log(0, "Failed to re-allocate %lu bytes.", - (unsigned long)d->size + grow); - clear_descr(d); - return -1; - } - d->size += grow; - d->buf = tmp; - } - return 0; -} - -/* - * Handle incoming data to the stream socket in `d[index]' - */ - -static void -handle_stream(struct descr *d, int index, int min_free) -{ - unsigned char buf[1024]; - int n; - int ret = 0; - - if (d[index].timeout == 0) { - add_new_stream (d, index, min_free); - return; - } - - if (update_client_creds(d[index].s, &d[index].peercred)) { - krb5_warnx(kcm_context, "failed to update peer identity"); - clear_descr(d + index); - return; - } - - if (d[index].peercred.uid == -1) { - krb5_warnx(kcm_context, "failed to determine peer identity"); - clear_descr (d + index); - return; - } - - n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL); - if (n < 0) { - krb5_warn(kcm_context, errno, "recvfrom"); - return; - } else if (n == 0) { - krb5_warnx(kcm_context, "connection closed before end of data " - "after %lu bytes from process %ld", - (unsigned long) d[index].len, (long) d[index].peercred.pid); - clear_descr (d + index); - return; - } - if (grow_descr (&d[index], n)) - return; - memcpy(d[index].buf + d[index].len, buf, n); - d[index].len += n; - if (d[index].len > 4) { - krb5_storage *sp; - int32_t len; - - sp = krb5_storage_from_mem(d[index].buf, d[index].len); - if (sp == NULL) { - kcm_log (0, "krb5_storage_from_mem failed"); - ret = -1; - } else { - krb5_ret_int32(sp, &len); - krb5_storage_free(sp); - if (d[index].len - 4 >= len) { - memmove(d[index].buf, d[index].buf + 4, d[index].len - 4); - ret = 1; - } else - ret = 0; - } - } - if (ret < 0) - return; - else if (ret == 1) { - do_request(d[index].buf, d[index].len, &d[index]); - clear_descr(d + index); - } -} - -#ifdef HAVE_DOOR_CREATE - -static void -kcm_door_server(void *cookie, char *argp, size_t arg_size, - door_desc_t *dp, uint_t n_desc) -{ - kcm_client peercred; - door_cred_t cred; - krb5_error_code ret; - krb5_data reply; - size_t length; - char *p; - - reply.length = 0; - - p = NULL; - length = 0; - - if (door_cred(&cred) != 0) { - kcm_log(0, "door_cred failed with %s", strerror(errno)); - goto out; - } - - peercred.uid = cred.dc_euid; - peercred.gid = cred.dc_egid; - peercred.pid = cred.dc_pid; - - ret = process_request((unsigned char*)argp, arg_size, &reply, &peercred); - if (reply.length != 0) { - p = alloca(reply.length); /* XXX don't use alloca */ - if (p) { - memcpy(p, reply.data, reply.length); - length = reply.length; - } - krb5_data_free(&reply); - } - - out: - door_return(p, length, NULL, 0); -} - -static void -kcm_setup_door(void) -{ - int fd, ret; - char *path; - - fd = door_create(kcm_door_server, NULL, 0); - if (fd < 0) - krb5_err(kcm_context, 1, errno, "Failed to create door"); - - if (door_path != NULL) - path = door_path; - else - path = _PATH_KCM_DOOR; - - unlink(path); - ret = open(path, O_RDWR | O_CREAT, 0666); - if (ret < 0) - krb5_err(kcm_context, 1, errno, "Failed to create/open door"); - close(ret); - - ret = fattach(fd, path); - if (ret < 0) - krb5_err(kcm_context, 1, errno, "Failed to attach door"); - -} -#endif /* HAVE_DOOR_CREATE */ - - -void -kcm_loop(void) -{ - struct descr *d; - int ndescr; - -#ifdef HAVE_DOOR_CREATE - kcm_setup_door(); -#endif - - ndescr = init_sockets(&d); - if (ndescr <= 0) { - krb5_warnx(kcm_context, "No sockets!"); -#ifndef HAVE_DOOR_CREATE - exit(1); -#endif - } - while (exit_flag == 0){ - struct timeval tmout; - fd_set fds; - int min_free = -1; - int max_fd = 0; - int i; - - FD_ZERO(&fds); - for(i = 0; i < ndescr; i++) { - if (d[i].s >= 0){ - if(d[i].type == SOCK_STREAM && - d[i].timeout && d[i].timeout < time(NULL)) { - kcm_log(1, "Stream connection from %d expired after %lu bytes", - d[i].peercred.pid, (unsigned long)d[i].len); - clear_descr(&d[i]); - continue; - } - if (max_fd < d[i].s) - max_fd = d[i].s; - if (max_fd >= FD_SETSIZE) - krb5_errx(kcm_context, 1, "fd too large"); - FD_SET(d[i].s, &fds); - } else if (min_free < 0 || i < min_free) - min_free = i; - } - if (min_free == -1) { - struct descr *tmp; - tmp = realloc(d, (ndescr + 4) * sizeof(*d)); - if(tmp == NULL) - krb5_warnx(kcm_context, "No memory"); - else { - d = tmp; - reinit_descrs (d, ndescr); - memset(d + ndescr, 0, 4 * sizeof(*d)); - for(i = ndescr; i < ndescr + 4; i++) - init_descr (&d[i]); - min_free = ndescr; - ndescr += 4; - } - } - - tmout.tv_sec = STREAM_TIMEOUT; - tmout.tv_usec = 0; - switch (select(max_fd + 1, &fds, 0, 0, &tmout)){ - case 0: - kcm_run_events(kcm_context, time(NULL)); - break; - case -1: - if (errno != EINTR) - krb5_warn(kcm_context, errno, "select"); - break; - default: - for(i = 0; i < ndescr; i++) { - if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) { - if (d[i].type == SOCK_STREAM) - handle_stream(d, i, min_free); - } - } - kcm_run_events(kcm_context, time(NULL)); - break; - } - } - if (d->path != NULL) - unlink(d->path); - free(d); -} - |