Permalink
Browse files

Interface for requesting privileged sockets in Erlang.

  • Loading branch information...
0 parents commit 441fde8410be77fbe09bcf53be7f888f76a9ff06 @msantos committed Jan 9, 2010
Showing with 1,334 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +6 −0 Emakefile
  3. +36 −0 Makefile
  4. +88 −0 README
  5. +71 −0 c_src/Makefile.ancillary
  6. +123 −0 c_src/ancillary.h
  7. +98 −0 c_src/fd_recv.c
  8. +92 −0 c_src/fd_send.c
  9. +239 −0 c_src/procket.c
  10. +101 −0 c_src/procket.h
  11. +235 −0 c_src/procket_cmd.c
  12. +74 −0 src/echo.erl
  13. +75 −0 src/mktmp.erl
  14. +94 −0 src/procket.erl
@@ -0,0 +1,2 @@
+*.[oa]
+*.beam
@@ -0,0 +1,6 @@
+{["src/*"],
+ [{i, "include"},
+ {outdir, "ebin"},
+ debug_info]
+}.
+
@@ -0,0 +1,36 @@
+
+ERL=erl
+APP=procket
+
+CC=gcc
+
+#ERL_LIB=/usr/local/lib/erlang
+ERL_ROOT=/media/opt/local/lib/erlang
+ARCH=-m32
+CFLAGS=-g -Wall
+FLAGS=-fPIC -shared
+
+
+all: dir erl ancillary nif cmd
+
+dir:
+ -@mkdir -p priv/tmp ebin
+
+erl:
+ @$(ERL) -noinput +B \
+ -eval 'case make:all() of up_to_date -> halt(0); error -> halt(1) end.'
+
+ancillary:
+ (cd c_src && $(MAKE) -f Makefile.ancillary)
+
+nif:
+ $(CC) -g -Wall $(FLAGS) -o priv/procket.so -L c_src \
+ c_src/procket.c -lancillary -I $(ERL_ROOT)/usr/include/
+
+cmd:
+ $(CC) -g -Wall -o priv/procket -L c_src c_src/procket_cmd.c -lancillary
+
+clean:
+ @rm -fv ebin/*.beam priv/$(APP) priv/$(APP).so c_src/*.a c_src/*.o
+
+
88 README
@@ -0,0 +1,88 @@
+
+procket is an Erlang interface for requesting socket features that
+usually require superuser privileges.
+
+procket uses the experimental NIF interface first introduced in Erlang
+R13B03.
+
+
+EXPORTS
+
+listen(Port, Options) -> {ok, FD} | {error, Reason} | {error, Reason, Description}
+
+ Types Port = 0..65535
+ Options = [Opts]
+ Opts = {pipe, Path} | {protocol, Protocol} | {ip, IPAddress} |
+ {progname, string()}
+ Protocol = tcp | udp
+ IPAddress = string() | tuple()
+
+
+SETUID vs SUDO
+
+The procket executable needs root privileges. Either allow your user to
+run procket using sudo or copy procket to somewhere owned by root and
+make it setuid.
+
+* for sudo
+
+ sudo visudo
+ youruser ALL=NOPASSWD: /path/to/procket/priv/procket
+
+* to make it setuid
+
+ sudo cp priv/procket /usr/local/bin
+ sudo chown root:yourgroup /usr/local/bin/procket
+ sudo chmod 750 /usr/local/bin/procket
+ sudo chmod u+s /usr/local/bin/procket
+
+
+USING IT
+
+$ erl -pa ebin
+Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false]
+
+Eshell V5.7.4 (abort with ^G)
+1> {ok, FD} = procket:listen(53, [{progname, "sudo priv/procket"},{protocol, udp}]).
+{ok,9}
+2> {ok, S} = gen_udp:open(53, [{fd,FD}]).
+{ok,#Port<0.929>}
+3> receive M -> M end.
+{udp,#Port<0.929>,{127,0,0,1},47483,"hello\n"}
+4>
+
+$ nc -u localhost 53
+hello
+^C
+
+
+EXAMPLE
+
+echo is a sample client using procket.
+
+$ erl -pa ebin
+1> echo:start(53, [{progname, "sudo priv/procket"}, {protocol, tcp}]).
+
+
+HOW IT WORKS
+
+procket creates a local domain socket and spawns a small setuid binary
+(or runs it under sudo). The executable opens a socket, drops privs and
+passes the file descriptor back to Erlang over the Unix socket.
+
+procket uses libanciallary for passing file descriptors between processes:
+
+ http://www.normalesup.org/~george/comp/libancillary/
+
+
+TODO
+
+* add an interface for setsockopt(2)
+
+* does Erlang close the passed in fd? add an interface to close() it
+
+* allow procket to manage more than one fd
+
+* experiment with providing an interface for supporting for raw sockets
+
+
@@ -0,0 +1,71 @@
+###########################################################################
+# libancillary - black magic on Unix domain sockets
+# (C) Nicolas George
+# Makefile - guess what
+###########################################################################
+
+# 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. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+CC=gcc
+CFLAGS=-Wall -g -O2
+LDFLAGS=
+LIBS=
+AR=ar
+RANLIB=ranlib
+RM=rm
+CP=cp
+MKDIR=mkdir
+TAR=tar
+GZIP=gzip -9
+
+NAME=libancillary
+DISTRIBUTION=API COPYING Makefile ancillary.h fd_send.c fd_recv.c test.c
+VERSION=0.9.1
+
+OBJECTS=fd_send.o fd_recv.o
+
+TUNE_OPTS=-DNDEBUG -DSPARE_SEND_FDS -DSPARE_RECV_FDS
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(TUNE_OPTS) $<
+
+all: libancillary.a
+
+libancillary.a: $(OBJECTS)
+ $(AR) cr $@ $(OBJECTS)
+ $(RANLIB) $@
+
+fd_send.o: ancillary.h
+fd_recv.o: ancillary.h
+
+test: test.c libancillary.a
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) -L. test.c -lancillary $(LIBS)
+
+clean:
+ -$(RM) -f *.o *.a test
+
+dist:
+ $(MKDIR) $(NAME)-$(VERSION)
+ $(CP) $(DISTRIBUTION) $(NAME)-$(VERSION)
+ $(TAR) -cf - $(NAME)-$(VERSION) | $(GZIP) > $(NAME)-$(VERSION).tar.gz
+ $(RM) -rf $(NAME)-$(VERSION)
@@ -0,0 +1,123 @@
+/***************************************************************************
+ * libancillary - black magic on Unix domain sockets
+ * (C) Nicolas George
+ * ancillary.h - public header
+ ***************************************************************************/
+
+/*
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef ANCILLARY_H__
+#define ANCILLARY_H__
+
+/***************************************************************************
+ * Start of the readable part.
+ ***************************************************************************/
+
+#define ANCIL_MAX_N_FDS 960
+/*
+ * Maximum number of fds that can be sent or received using the "esay"
+ * functions; this is so that all can fit in one page.
+ */
+
+extern int
+ancil_send_fds_with_buffer(int, const int *, unsigned, void *);
+/*
+ * ancil_send_fds_with_buffer(sock, n_fds, fds, buffer)
+ *
+ * Sends the file descriptors in the array pointed by fds, of length n_fds
+ * on the socket sock.
+ * buffer is a writeable memory area large enough to hold the required data
+ * structures.
+ * Returns: -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fds_with_buffer(int, int *, unsigned, void *);
+/*
+ * ancil_recv_fds_with_buffer(sock, n_fds, fds, buffer)
+ *
+ * Receives *n_fds file descriptors into the array pointed by fds
+ * from the socket sock.
+ * buffer is a writeable memory area large enough to hold the required data
+ * structures.
+ * Returns: -1 and errno in case of error, the actual number of received fd
+ * in case of success
+ */
+
+#define ANCIL_FD_BUFFER(n) \
+ struct { \
+ struct cmsghdr h; \
+ int fd[n]; \
+ }
+/* ANCIL_FD_BUFFER(n)
+ *
+ * A structure type suitable to be used as buffer for n file descriptors.
+ * Requires <sys/socket.h>.
+ * Example:
+ * ANCIL_FD_BUFFER(42) buffer;
+ * ancil_recv_fds_with_buffer(sock, 42, my_fds, &buffer);
+ */
+
+extern int
+ancil_send_fds(int, const int *, unsigned);
+/*
+ * ancil_send_fds(sock, n_fds, fds)
+ *
+ * Sends the file descriptors in the array pointed by fds, of length n_fds
+ * on the socket sock.
+ * n_fds must not be greater than ANCIL_MAX_N_FDS.
+ * Returns: -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fds(int, int *, unsigned);
+/*
+ * ancil_recv_fds(sock, n_fds, fds)
+ *
+ * Receives *n_fds file descriptors into the array pointed by fds
+ * from the socket sock.
+ * *n_fds must not be greater than ANCIL_MAX_N_FDS.
+ * Returns: -1 and errno in case of error, the actual number of received fd
+ * in case of success.
+ */
+
+
+extern int
+ancil_send_fd(int, int);
+/* ancil_recv_fd(sock, fd);
+ *
+ * Sends the file descriptor fd on the socket sock.
+ * Returns : -1 and errno in case of error, 0 in case of success.
+ */
+
+extern int
+ancil_recv_fd(int, int *);
+/* ancil_send_fd(sock, &fd);
+ *
+ * Receives the file descriptor fd from the socket sock.
+ * Returns : -1 and errno in case of error, 0 in case of success.
+ */
+
+#endif /* ANCILLARY_H__ */
Oops, something went wrong.

0 comments on commit 441fde8

Please sign in to comment.