From owner-p4-projects@FreeBSD.ORG Mon Jun 15 17:56:16 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6F037106566C; Mon, 15 Jun 2009 17:56:16 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2E60D106564A for ; Mon, 15 Jun 2009 17:56:16 +0000 (UTC) (envelope-from jona@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 1AE168FC08 for ; Mon, 15 Jun 2009 17:56:16 +0000 (UTC) (envelope-from jona@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5FHuGb9020645 for ; Mon, 15 Jun 2009 17:56:16 GMT (envelope-from jona@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5FHuGVw020643 for perforce@freebsd.org; Mon, 15 Jun 2009 17:56:16 GMT (envelope-from jona@FreeBSD.org) Date: Mon, 15 Jun 2009 17:56:16 GMT Message-Id: <200906151756.n5FHuGVw020643@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jona@FreeBSD.org using -f From: Jonathan Anderson To: Perforce Change Reviews Cc: Subject: PERFORCE change 164441 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Jun 2009 17:56:17 -0000 http://perforce.freebsd.org/chv.cgi?CH=164441 Change 164441 by jona@jona-trustedbsd-belle-vm on 2009/06/15 17:55:46 Sandbox/angel RPC to request single files and powerboxes Affected files ... .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/Makefile#5 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/cap.c#3 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/fdtest.c#4 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/powerbox.c#3 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/powerbox.h#3 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/protocol.c#8 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/protocol.h#7 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/server.c#4 edit .. //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/test_client.c#4 edit Differences ... ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/Makefile#5 (text+ko) ==== @@ -1,25 +1,22 @@ -CFLAGS=-g -ggdb --std=c99 -Wall -Werror #-pedantic-errors +VERSION=dev-pre1 +CFLAGS=-g -ggdb --std=c99 -Wall -Werror -pedantic-errors -DVERSION='"${VERSION}"' +LDFLAGS=-L/usr/local/lib -lefence -BIN=user_angel test_client fdtest -AGENT_OBJ = user_angel.o server.o cap.o protocol.o fdcomm.o powerbox.o -CLIENT_OBJ = test_client.o protocol.o fdcomm.o +BIN=user_angel test_client +AGENT_OBJ = user_angel.o server.o cap.o protocol.o powerbox.o +CLIENT_OBJ = test_client.o protocol.o all: ${BIN} user_angel: ${AGENT_OBJ} - ${CC} -o $@ ${AGENT_OBJ} + ${CC} ${LDFLAGS} -o $@ ${AGENT_OBJ} test_client: ${CLIENT_OBJ} - ${CC} -o $@ ${CLIENT_OBJ} + ${CC} ${LDFLAGS} -o $@ ${CLIENT_OBJ} -fdtest: fdtest.o fdcomm.o protocol.o - ${CC} -o $@ fdtest.o fdcomm.o protocol.o - cap.o: cap.c cap.h -fdcomm.o: fdcomm.c fdcomm.h -fdtest.o: fdtest.c protocol.h powerbox.o: powerbox.c powerbox.h protocol.o: protocol.c protocol.h powerbox.h server.o: server.c protocol.h server.h ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/cap.c#3 (text+ko) ==== @@ -47,6 +47,7 @@ int cap = cap_new(fd, rights); if(cap < 0) err(EX_SOFTWARE, "failed to create new capability"); + close(fd); return cap; } ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/fdtest.c#4 (text+ko) ==== @@ -85,7 +85,7 @@ struct cap_wire_datum *d = cap_marshall_string(message, strlen(message)); - if(cap_send_fd(sock, "message and FDs", d, fds, fdlen) < 0) + if(cap_send_fd(sock, d, fds, fdlen) < 0) err(EX_IOERR, "Error sending data/FD"); free(d); @@ -94,9 +94,8 @@ int fd_array[10]; fdlen = 10; - char *name; - if(cap_recv_fd(sock, &name, &d, fd_array, &fdlen) < 0) - err(EX_IOERR, "Error receiving data/FD"); + d = cap_recv_fds(sock, fd_array, &fdlen); + if(!d) err(EX_IOERR, "Error receiving data/FD"); printf("Received datum:\n"); printf(" type: %i\n", d->type); ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/powerbox.c#3 (text+ko) ==== @@ -34,12 +34,16 @@ #include __FBSDID("$FreeBSD$"); +#include #include +#include +#include #include "powerbox.h" -int capbox_display(struct capbox_options *options) +int capbox_display(struct capbox_options *options, int fds[], char *names[], + int *len) { printf("capbox_display()\n"); printf(" options:\n"); @@ -73,8 +77,26 @@ if(options->filterlen > 0) printf("%s\n", options->filter); else printf("\n"); - fprintf(stderr, "powerbox not implemented\n"); + fprintf(stderr, "powerbox not implemented, faking it\n"); + + if(*len > 0) + { + names[0] = (char*) malloc(32); + strcpy(names[0], "/etc/hosts"); + + fds[0] = open("/etc/hosts", O_RDONLY); + } + + if(*len > 1) + { + names[1] = (char*) malloc(32); + strcpy(names[1], "/etc/nsswitch.conf"); + + fds[1] = open("/etc/nsswitch.conf", O_RDONLY); + } + + if(*len > 2) *len = 2; - return -1; + return 0; } ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/powerbox.h#3 (text+ko) ==== @@ -48,11 +48,11 @@ enum capbox_op_t operation; /* operation to perform */ char* window_title; /* set by user_angel, not sandbox */ int parent_window; /* X11 window to attach to (or 0) */ - char* start_path; /* path to start in (or NULL) */ + const char* start_path; /* path to start in (or NULL) */ int pathlen; /* length of start path */ int start_fd; /* FD to start in (or -1) */ int mult; /* allow multiple selection */ - char* filter; /* filter expression (or NULL) */ + const char* filter; /* filter expression (or NULL) */ int filterlen; /* length of filter expression */ }; @@ -60,7 +60,8 @@ /** * Open a powerbox. * - * @return a capability file descriptor or -1 + * @return 0 on success */ -int capbox_display(struct capbox_options *options); +int capbox_display(struct capbox_options *options, int fds[], char *names[], + int *len); ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/protocol.c#8 (text+ko) ==== @@ -45,85 +45,305 @@ -struct cap_wire_datum* cap_marshall_int(int32_t value) + + +void print_datum(const struct cap_wire_datum *d) +{ + printf("Datum @ 0x%8x:\n", (unsigned int) d); + printf(" type: %i\n", d->type); + printf(" length: %i\n", d->length); + printf(" data: "); + for(int j = 0; j < d->length; j++) + { + unsigned char *address = ((unsigned char*) d); + address += sizeof(struct cap_wire_datum) + j; + + printf("%02x ", *address); + } + printf("\n"); +} + + + + +typedef struct cap_wire_datum wire_datum; + + +char errmsg[256]; +const char* cap_error(void) { return errmsg; } + + +wire_datum* cap_marshall_int(int32_t value) { - int size = sizeof(struct cap_wire_datum) + sizeof(int32_t); - struct cap_wire_datum *d = (struct cap_wire_datum*) malloc(size); + int size = sizeof(wire_datum) + sizeof(int32_t); + wire_datum *d = (wire_datum*) malloc(size); d->type = INTEGER; d->length = sizeof(int32_t); - ((int32_t*) d + sizeof(struct cap_wire_datum))[0] = value; + + void *address = ((char*) d) + sizeof(wire_datum); + ((int32_t*) address)[0] = value; return d; } -int cap_unmarshall_int(struct cap_wire_datum *datum, int32_t *value) +int cap_unmarshall_int(const wire_datum *datum, int32_t *value) { + if(datum == NULL) + { + sprintf(errmsg, "Datum is NULL"); + return -1; + } + + if(!(datum->type & INTEGER)) + { + sprintf(errmsg, "Datum's type is %i, not INTEGER (%i)", + datum->type, INTEGER); + return -1; + } + if(datum->length != 4) { - fprintf(stderr, "Error unmarshalling int: should be 4B long, not %i\n", - datum->length); + sprintf(errmsg, "An 32-bit integer should be 4B long, not %i", + datum->length); return -1; } - memcpy(value, ((void*) datum) + sizeof(struct cap_wire_datum), 4); + memcpy(value, ((char*) datum) + sizeof(wire_datum), 4); return datum->length; } -struct cap_wire_datum* cap_marshall_string(char *value, int len) +wire_datum* cap_marshall_string(const char *value, int len) { - int size = sizeof(struct cap_wire_datum) + len; - struct cap_wire_datum *d = (struct cap_wire_datum*) malloc(size); + int size = sizeof(wire_datum) + len; + wire_datum *d = (wire_datum*) malloc(size); d->type = STRING; d->length = len; - memcpy(((char*) d) + sizeof(struct cap_wire_datum), value, len); + memcpy(((char*) d) + sizeof(wire_datum), value, len); return d; } -int cap_unmarshall_string(struct cap_wire_datum *datum, char *value, int *len) +int cap_unmarshall_string(const wire_datum *datum, char *value, int *len) { + if(datum == NULL) + { + sprintf(errmsg, "NULL datum"); + return -1; + } + else if(datum->type != STRING) + { + sprintf(errmsg, "Datum's type is %i, not STRING (%i)", + datum->type, STRING); + } + else if(datum->length < 0) + { + sprintf(errmsg, "Datum length should be positive, not %i", + datum->length); + return -1; + } + else if(datum->length >= *len) + { + sprintf(errmsg, "String in datum is too long (%iB) to fit in buffer (%iB)", + datum->length, *len); + return -1; + } + *len = datum->length; - if(datum->length < 0) + memcpy(value, ((char*) datum) + sizeof(wire_datum), datum->length); + value[*len] = '\0'; + + return datum->length; +} + + +wire_datum* cap_marshall_capbox(const struct capbox_options *options) +{ + wire_datum *data[6]; + data[0] = cap_marshall_int(options->ui); + data[1] = cap_marshall_int(options->operation); + data[2] = cap_marshall_int(options->parent_window); + data[3] = cap_marshall_string(options->start_path, options->pathlen); + data[4] = cap_marshall_int(options->mult); + data[5] = cap_marshall_string(options->filter, options->filterlen); + + int total_size = 0; + for(int i = 0; i < 6; i++) + if(data[i] == NULL) + { + sprintf(errmsg, "Capbox datum %i is NULL", i); + return NULL; + } + else total_size += (sizeof(wire_datum) + data[i]->length); + + wire_datum *d = (wire_datum*) malloc(sizeof(wire_datum) + total_size); + d->type = CAPBOX_OPTIONS; + d->length = total_size; + + char *buffer = ((char*) d) + sizeof(wire_datum); + char *head = buffer; + for(int i = 0; i < 6; i++) + { + memcpy(head, data[i], sizeof(wire_datum) + data[i]->length); + head += sizeof(wire_datum) + data[i]->length; + + free(data[i]); + } + + return d; +} + + +int cap_unmarshall_capbox(const wire_datum *datum, struct capbox_options *options) +{ + if(datum == NULL) + { + sprintf(errmsg, "NULL datum"); + return -1; + } + else if(datum->type != CAPBOX_OPTIONS) + { + sprintf(errmsg, "Datum's type is %i, not CAPBOX_OPTIONS (%i)", + datum->type, CAPBOX_OPTIONS); + } + else if(datum->length < 0) { - fprintf(stderr, "Error unmarshalling int: should be positive, not %i\n", + sprintf(errmsg, "Datum length should be positive, not %i", datum->length); return -1; } - memcpy(value, ((void*) datum) + sizeof(struct cap_wire_datum), datum->length); - return datum->length; + int32_t tmp_int; + wire_datum *d = (wire_datum*) (((char*) datum) + sizeof(wire_datum)); + + if(cap_unmarshall_int(d, &tmp_int) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling UI type: %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + options->ui = tmp_int; + d = (wire_datum*) (((char*) d) + sizeof(wire_datum) + d->length); + + if(cap_unmarshall_int(d, &tmp_int) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling operation: %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + options->operation = tmp_int; + d = (wire_datum*) (((char*) d) + sizeof(wire_datum) + d->length); + + + // window title is handled elsewhere + + + if(cap_unmarshall_int(d, &tmp_int) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling parent: %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + options->parent_window = tmp_int; + d = (wire_datum*) (((char*) d) + sizeof(wire_datum) + d->length); + + options->pathlen = d->length + 1; + options->start_path = (char*) malloc(options->pathlen); + if(cap_unmarshall_string(d, (char*) options->start_path, &options->pathlen) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling path: %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + d = (wire_datum*) (((char*) d) + sizeof(wire_datum) + d->length); + + + // don't do anything about the start_fd file descriptor; + // that's handled at the recvmsg() level + + + if(cap_unmarshall_int(d, &tmp_int) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling 'mult': %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + options->mult = tmp_int; + d = (wire_datum*) (((char*) d) + sizeof(wire_datum) + d->length); + + options->filterlen = d->length + 1; + options->filter = (char*) malloc(options->filterlen); + if(cap_unmarshall_string(d, (char*) options->filter, &options->filterlen) < 0) + { + char error[128]; + sprintf(error, "Error unmarshalling filter: %s", cap_error()); + strcpy(errmsg, error); + return -1; + } + + + return sizeof(wire_datum) + datum->length; +} + + + +int cap_send_message(int sock, wire_datum *data[], int len) +{ + int total_bytes = 0; + for(int i = 0; i < len; i++) + { + int bytes = cap_send(sock, data[i]); + + if(bytes < 0) return bytes; + else total_bytes += bytes; + } + + return total_bytes; +} + + + +int cap_send(int sock, wire_datum *datum) +{ + return cap_send_fd(sock, datum, NULL, 0); } -/* -int cap_send(int sock, struct cap_wire_datum* datum); -*/ -int cap_send_fd(int sock, const char *name, struct cap_wire_datum *d, +int cap_send_fd(int sock, wire_datum *d, int32_t fd_array[], int32_t fdlen) { // the datum is the I/O vector struct iovec iov; iov.iov_base = d; - iov.iov_len = sizeof(struct cap_wire_datum) + d->length; + iov.iov_len = sizeof(wire_datum) + d->length; // ancilliary data (file descriptors) - int cmsghdrlen = sizeof(struct cmsghdr) + fdlen * sizeof(int32_t); - struct cmsghdr *anc_hdr = (struct cmsghdr*) malloc(cmsghdrlen); - if(!anc_hdr) err(EX_OSERR, "Error creating ancilliary data header"); + struct cmsghdr *anc_hdr = NULL; + if(fdlen > 0) + { + int cmsghdrlen = sizeof(struct cmsghdr) + fdlen * sizeof(int32_t); + anc_hdr = (struct cmsghdr*) malloc(cmsghdrlen); + if(!anc_hdr) err(EX_OSERR, "Error creating ancilliary data header"); + + anc_hdr->cmsg_len = cmsghdrlen; + anc_hdr->cmsg_level = SOL_SOCKET; + anc_hdr->cmsg_type = (fdlen ? SCM_RIGHTS : 0); + memcpy(((char*) anc_hdr) + sizeof(struct cmsghdr), fd_array, + fdlen * sizeof(int32_t)); + } - anc_hdr->cmsg_len = cmsghdrlen; - anc_hdr->cmsg_level = SOL_SOCKET; - anc_hdr->cmsg_type = SCM_RIGHTS; - memcpy(((void*) anc_hdr) + sizeof(struct cmsghdr), fd_array, - fdlen * sizeof(int32_t)); // sendmsg header @@ -133,7 +353,7 @@ header.msg_iov = &iov; header.msg_iovlen = 1; header.msg_control = anc_hdr; - header.msg_controllen = anc_hdr->cmsg_len; + header.msg_controllen = ((fdlen > 0) ? anc_hdr->cmsg_len : 0); header.msg_flags = 0; @@ -142,6 +362,7 @@ if(bytes_sent < 0) { perror("Error sending data and file descriptor(s)"); + free(anc_hdr); return -1; } @@ -151,37 +372,50 @@ } +wire_datum* cap_recv(int sock) +{ + int fdlen = 0; + return cap_recv_fds(sock, NULL, &fdlen); +} + -int cap_recv_fd(int sock, char **name, struct cap_wire_datum **d, - int32_t *fd_array, int32_t *fdlen) +wire_datum* cap_recv_fds(int sock, int32_t fd_array[], int32_t *fdlen) { // how much data is there to receive? - struct cap_wire_datum peek; - int bytes = recv(sock, &peek, sizeof(struct cap_wire_datum), MSG_PEEK); - if(bytes < 0) + wire_datum peek; + int bytes = recv(sock, &peek, sizeof(wire_datum), MSG_PEEK); + + if(bytes == 0) + { + sprintf(errmsg, "Socket closed: %s", strerror(errno)); + return NULL; + } + else if(bytes < 0) { perror("Error peeking at socket"); - return -1; + return NULL; } - int to_receive = sizeof(struct cap_wire_datum) + peek.length; + int to_receive = sizeof(wire_datum) + peek.length; // make room for it - *d = (struct cap_wire_datum*) malloc(to_receive); + wire_datum *datum = (wire_datum*) malloc(to_receive); struct iovec iov; - iov.iov_base = *d; + iov.iov_base = datum; iov.iov_len = to_receive; // prepare to receive file descriptor(s) - int size = sizeof(struct cmsghdr) + *fdlen; + int size = sizeof(struct cmsghdr) + *fdlen * sizeof(int32_t); struct cmsghdr *anc_hdr = (struct cmsghdr*) malloc(size); + bzero(anc_hdr, size); + if(!anc_hdr) err(EX_OSERR, "Error creating ancilliary data header"); anc_hdr->cmsg_len = size; anc_hdr->cmsg_level = SOL_SOCKET; - anc_hdr->cmsg_type = SCM_RIGHTS; - memset(anc_hdr + sizeof(struct cmsghdr), 0, *fdlen * sizeof(int32_t)); + anc_hdr->cmsg_type = (*fdlen ? SCM_RIGHTS : 0); + bzero(anc_hdr + sizeof(struct cmsghdr), *fdlen * sizeof(int32_t)); // recvmsg() options struct msghdr header; @@ -198,12 +432,16 @@ if(bytes < 0) { perror("Error receiving message"); - return -1; + free(anc_hdr); + free(datum); + return NULL; } else if(bytes == 0) { fprintf(stderr, "Socket closed\n"); - return -1; + free(anc_hdr); + free(datum); + return NULL; } @@ -212,10 +450,12 @@ if(recv_fdlen < *fdlen) *fdlen = recv_fdlen; - memcpy(fd_array, ((void*) anc_hdr) + sizeof(struct cmsghdr), + memcpy(fd_array, ((char*) anc_hdr) + sizeof(struct cmsghdr), *fdlen * sizeof(int32_t)); - return 0; + free(anc_hdr); + + return datum; } @@ -282,7 +522,7 @@ return total_bytes; } - +/* int cap_send_capbox_options(int client, struct capbox_options *options) { int bytes, total_bytes = 0; @@ -302,11 +542,11 @@ bytes = cap_send_string(client, options->start_path, options->pathlen); if(bytes <= 0) return bytes; total_bytes += bytes; -/* TODO: need to do a sendmsg with SCM_RIGHTS +* TODO: need to do a sendmsg with SCM_RIGHTS bytes = cap_send_int(client, options->start_fd); if(bytes <= 0) return bytes; total_bytes += bytes; -*/ +* bytes = cap_send_int(client, options->mult); if(bytes <= 0) return bytes; total_bytes += bytes; @@ -340,11 +580,11 @@ total_bytes += bytes; options->pathlen = bytes; -/* TODO: need to do a sendmsg with SCM_RIGHTS +* TODO: need to do a sendmsg with SCM_RIGHTS bytes = cap_recv_int(client, &options->start_fd); if(bytes <= 0) { perror("Error receiving path FD"); return bytes; } total_bytes += bytes; -*/ +* options->start_fd = -1; bytes = cap_recv_int(client, &options->mult); @@ -359,4 +599,5 @@ return total_bytes; } +*/ ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/protocol.h#7 (text+ko) ==== @@ -35,6 +35,22 @@ #include "powerbox.h" + +/** Requests that clients can make */ +enum capangel_req_t +{ + NO_OP = 0, + FD_FROM_PATH, + FD_POWERBOX +}; + + +/** The last protocol error */ +const char* cap_error(void); + + + +/** Represents a single datum "on the wire" */ struct cap_wire_datum { uint32_t type; @@ -51,49 +67,35 @@ uint32_t length; - /* followed by data; */ + /* immediately followed by actual data; */ }; -/** Requests that clients can make */ -enum capangel_req_t -{ - FD_FROM_PATH, - FD_POWERBOX -}; - - - /* Unmarshalling functions; calling programs should free the result */ struct cap_wire_datum* cap_marshall_int(int32_t value); -struct cap_wire_datum* cap_marshall_string(char *value, int len); +struct cap_wire_datum* cap_marshall_string(const char *value, int len); +struct cap_wire_datum* cap_marshall_capbox(const struct capbox_options *options); + /* Unmarshalling functions; return the number of bytes unmarshalled (or -1) */ -int cap_unmarshall_int(struct cap_wire_datum *datum, int32_t *value); -int cap_unmarshall_string(struct cap_wire_datum *datum, char* value, int *len); +int cap_unmarshall_int(const struct cap_wire_datum *d, int32_t *value); +int cap_unmarshall_string(const struct cap_wire_datum *d, char* value, int *len); +int cap_unmarshall_capbox(const struct cap_wire_datum *d, struct capbox_options *options); + -/* Sending, with or without file descriptors */ -int cap_send(int sock, char *name, struct cap_wire_datum *d); -int cap_send_fd(int sock, const char *name, struct cap_wire_datum *d, +/* Sending, with (_fd) or without file descriptors */ +int cap_send(int sock, struct cap_wire_datum *d); +int cap_send_fd(int sock, struct cap_wire_datum *d, int32_t fd_array[], int32_t fdlen); +int cap_send_message(int sock, struct cap_wire_datum *data[], int len); + /* Receiving, with or without file descriptors */ -int cap_recv(int sock, char **name, struct cap_wire_datum **d); +struct cap_wire_datum* cap_recv(int sock); /* You supply the FD array and say how big it is; I'll tell you how many FDs you actually received. */ -int cap_recv_fd(int sock, char **name, struct cap_wire_datum **d, - int32_t fd_array[], int32_t *fdlen); - +struct cap_wire_datum* cap_recv_fds(int sock, int32_t fd_array[], int32_t *fdlen); -int cap_send_int(int client, int value); -int cap_recv_int(int client, int *value); - -int cap_send_string(int client, char *value, int len); -int cap_recv_string(int client, char **value); - -int cap_send_capbox_options(int client, struct capbox_options *options); -int cap_recv_capbox_options(int client, struct capbox_options *options); - ==== //depot/projects/trustedbsd/capabilities/src/tools/cap/user_angel/server.c#4 (text+ko) ==== @@ -31,9 +31,6 @@ * SUCH DAMAGE. */ -#include -__FBSDID("$FreeBSD$"); - #include #include #include @@ -46,7 +43,6 @@ #include #include "cap.h" -#include "fdcomm.h" #include "protocol.h" #include "server.h" @@ -55,9 +51,8 @@ int shutting_down = 0; char control_socket_name[256] = ""; -int *clients; -int clientslen; -int clientsmaxlen; +struct fd_set sockets; +int highest_fd; void user_angel_server_shutdown(void) @@ -76,15 +71,13 @@ int bind_to_path(const char *path); void accept_client(int fd_server); void service_clients(void); +void serve(int fd_server, struct fd_set *sockets); +void client_closed(int client); int run_server(const char* address) { - clientslen = 0; - clients = (int*) malloc (128 * sizeof(int)); - clientsmaxlen = 128; - strcpy(control_socket_name, address); printf("Creating control socket at %s...\n", control_socket_name); @@ -97,12 +90,7 @@ } - while(fd_control) - { - accept_client(fd_control); - service_clients(); - } - + while(fd_control) serve(fd_control, &sockets); user_angel_server_shutdown(); return 0; @@ -111,13 +99,15 @@ int bind_to_path(const char *path) { + FD_ZERO(&sockets); + struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, control_socket_name); int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd == 0) + if(fd < 0) { if(shutting_down) return 0; @@ -126,6 +116,12 @@ return -1; } + highest_fd = fd; + +/* + TODO: do this? + rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on));*/ if(bind(fd, (struct sockaddr*) &addr, sizeof(struct sockaddr_un))) { @@ -148,7 +144,7 @@ // non-blocking socket I/O - int flags = fcntl(fd, F_GETFL, 0); +/* int flags = fcntl(fd, F_GETFL, 0); if(flags < 0) { perror("Error getting flags for control socket"); @@ -159,7 +155,10 @@ { perror("Error setting flags on control socket"); return -1; - } + }*/ + + FD_SET(fd, &sockets); + return fd; @@ -185,116 +184,208 @@ return; } - printf("Accepted client: FD %i\n", client); + printf("Client %4i: Accepted\n", client); - clients[clientslen++] = client; + FD_SET(client, &sockets); + if(client > highest_fd) highest_fd = client; - if(clientslen == clientsmaxlen) - { - int newsize = 2 * clientsmaxlen; - int *newclients = (int*) malloc(newsize * sizeof(int)); + char hello[80]; + sprintf(hello, "user_angel v%s", VERSION); + struct cap_wire_datum *d = cap_marshall_string(hello, strlen(hello)); - memcpy(newclients, clients, clientslen * sizeof(int)); - free(clients); - clients = newclients; - clientslen = newsize; - } + cap_send(client, d); + free(d); } -void service_clients(void) + +void serve(int fd_server, struct fd_set *sockets) { - enum capangel_req_t req; + struct fd_set selected; + memcpy(&selected, sockets, sizeof(*sockets)); + - for(int i = 0; i < clientslen; i++) + int ready = select(highest_fd + 1, &selected, NULL, NULL, NULL); + if(ready < 0) + { + perror("select() failed"); + return; + } + else if(ready == 0) { - int client = clients[i]; - if(client == -1) continue; + perror("select() timed out"); + return; + } - int bytes = cap_recv_int(client, (int*) &req); - - if(bytes > 0) + for(int i = 0; (i <= highest_fd) && (ready > 0); i++) + { + if(FD_ISSET(i, &selected)) { - if(handle_request(client, req)) + if(i == fd_server) accept_client(i); + else { - perror("Error handling client request"); - close(client); - clients[i] = -1; + enum capangel_req_t req; + struct cap_wire_datum *d = cap_recv(i); + + if(!d) + { + if((errno == ENOENT) || (errno == ECONNRESET)) client_closed(i); + else perror("Error receiving from client"); + + continue; + } + + + int bytes = 0; + if(sizeof(enum capangel_req_t) == sizeof(int32_t)) + bytes = cap_unmarshall_int(d, (int32_t*) &req); + + else + { + fprintf(stderr, "enum size is %iB\n", sizeof(enum capangel_req_t)); + return; + } + + if(bytes < 0) + { + fprintf(stderr, "Error unmarshalling request: %s\n", cap_error()); + continue; + } + + if(handle_request(i, req)) + { + perror("Error handling client request"); + client_closed(i); + } } - } - else if(errno == EAGAIN) continue; - else - { - if(shutting_down) return; - perror("Error recv()'ing from client"); - break; + ready--; } } } - int handle_request(int client, enum capangel_req_t req) { - printf("Client %i requests ", client); + printf("Client %4i: ", client); + + struct cap_wire_datum *d; + int pathlen = 256; + char path[pathlen]; + int fds[32]; + int fdlen; switch(req) { case FD_FROM_PATH: >>> TRUNCATED FOR MAIL (1000 lines) <<<