diff --git a/CMakeLists.txt b/CMakeLists.txt index 8021f0a..5a59af8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,3 @@ -project(ndhc) - cmake_minimum_required(VERSION 3.3) if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) @@ -7,6 +5,8 @@ else() cmake_policy(VERSION 3.12) endif() +project (ndhc DESCRIPTION "dhcp4 client" LANGUAGES C) + #################################### # Computes the realtionship between two version strings. A version @@ -101,6 +101,31 @@ if (NOT (${OSNAME} STREQUAL "Linux")) return() endif() +if (${OSNAME} STREQUAL "Linux") + execute_process( + COMMAND uname -r + COMMAND tr "\n" " " + COMMAND sed "s/ //" + OUTPUT_VARIABLE LINUX_VERSION + ) + COMPARE_VERSION_STRINGS(${LINUX_VERSION} "3.5" LINUX_HAS_NO_NEW_PRIVS) + if (NOT ${LINUX_HAS_NO_NEW_PRIVS} LESS 0) + message("ncmlib: Enabling use of prctl SET_NO_NEW_PRIVS.") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNK_USE_NO_NEW_PRIVS") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNK_USE_NO_NEW_PRIVS") + else() + message("ncmlib: prctl SET_NO_NEW_PRIVS not available.") + endif() + COMPARE_VERSION_STRINGS(${LINUX_VERSION} "3.17" LINUX_HAS_GETRANDOM_SYSCALL) + if (NOT ${LINUX_HAS_GETRANDOM_SYSCALL} LESS 0) + message("ncmlib: Enabling use of getrandom syscall.") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNK_USE_GETRANDOM_SYSCALL") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNK_USE_GETRANDOM_SYSCALL") + else() + message("ncmlib: getrandom syscall not available.") + endif() +endif() + if (NOT CMAKE_CROSSCOMPILING) set(GLIBC_DETECT_TEST_C " @@ -139,5 +164,66 @@ else() set(MACHINENAME $ENV{CROSSCOMPILE_MACHINENAME}) endif() -add_subdirectory(ncmlib) -add_subdirectory(src) +add_executable(ndhc "") + +set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.c) +set(RAGEL_CFG_PARSE ${CMAKE_CURRENT_BINARY_DIR}/cfg.c) + +find_program(RAGEL ragel) + +set(RAGEL_PRINT_COMMENT "Compiling Ragel state machine: FILE") +file(GLOB_RECURSE RAGEL_FILES + "src/ifchd-parse.rl" + "src/cfg.rl" + ) +foreach(RAGEL_FILE ${RAGEL_FILES}) + string(REGEX REPLACE "^[^/]*[/]" "" RAGEL_FILE_BASE ${RAGEL_FILE}) + string(REGEX REPLACE ${RAGEL_FILE_BASE} "" RAGEL_FILE_PATH ${RAGEL_FILE}) + string(REGEX REPLACE "[.]rl$" ".c" RAGEL_FILE_C ${RAGEL_FILE_BASE}) + string(REGEX REPLACE "FILE$" ${RAGEL_FILE_BASE} RAGEL_COMMENT ${RAGEL_PRINT_COMMENT}) + set(RAGEL_FILE_C_OUT ${CMAKE_CURRENT_BINARY_DIR}/${RAGEL_FILE_C}) + list(APPEND RAGEL_C_FILES ${RAGEL_FILE_C_OUT}) + add_custom_command( + OUTPUT ${RAGEL_FILE_C_OUT} + COMMAND ${RAGEL} -T0 ${RAGEL_ERRFMT_ARG} -o ${RAGEL_FILE_C_OUT} ${RAGEL_FILE_BASE} + MAIN_DEPENDENCY ${RAGEL_FILE} + WORKING_DIRECTORY ${RAGEL_FILE_PATH} + COMMENT ${RAGEL_COMMENT} + VERBATIM + ) + set_property(SOURCE ${RAGEL_FILE_C_OUT} APPEND PROPERTY GENERATED TRUE) + if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set_property(SOURCE ${RAGEL_FILE_C_OUT} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable") + endif() + set_source_files_properties(${RAGEL_FILE_C_OUT} PROPERTIES GENERATED true) + target_sources(ndhc PRIVATE ${RAGEL_FILE_C_OUT}) +endforeach(RAGEL_FILE) +add_custom_target(ndhc_ragel DEPENDS ${RAGEL_C_FILES}) +add_dependencies(ndhc ndhc_ragel) + +target_sources(ndhc PRIVATE + "src/lib/io.c" + "src/lib/log.c" + "src/lib/hwrng.c" + "src/lib/random.c" + "src/lib/privs.c" + ${RAGEL_C_FILES} + "src/arp.c" + "src/ifchd.c" + "src/netlink.c" + "src/sockd.c" + "src/dhcp.c" + "src/ifset.c" + "src/nl.c" + "src/state.c" + "src/duiaid.c" + "src/leasefile.c" + "src/options.c" + "src/sys.c" + "src/ifchange.c" + "src/ndhc.c" + "src/rfkill.c" +) +target_include_directories(ndhc PRIVATE + "${PROJECT_SOURCE_DIR}/src" + ) diff --git a/Makefile b/Makefile index dc8eef8..8b71279 100644 --- a/Makefile +++ b/Makefile @@ -2,48 +2,42 @@ # for distros that want to avoid build dependencies. Produced exes will be # at './build/ndhc'. -NCM_SRCS = $(sort $(wildcard ncmlib/*.c)) +NCM_SRCS = $(sort $(wildcard src/lib/*.c)) NDHC_SRCS = $(sort $(wildcard src/*.c)) NCM_OBJS = $(NCM_SRCS:.c=.o) NDHC_OBJS = $(NDHC_SRCS:.c=.o) -NCM_INC = -I./ncmlib NDHC_INC = -I./src BUILD_DIR = build OBJ_DIR = $(BUILD_DIR)/objs CC = gcc AR = ar -RANLIB = ranlib CFLAGS = -O2 -s -std=gnu99 -pedantic -Wall -D_GNU_SOURCE # Not required for glibc >= 2.17, but older glibcs are still common. # The CMake build script will perform detection, but this Makefile is simple. LINK_LIBS = -lrt -all: makedir ifchd-parse.o cfg.o ncmlib.a ndhc +all: makedir ifchd-parse.o cfg.o ndhc clean: rm -Rf $(BUILD_DIR) makedir: - mkdir -p $(BUILD_DIR) $(OBJ_DIR)/src $(OBJ_DIR)/ncmlib + mkdir -p $(BUILD_DIR) $(OBJ_DIR)/src ifchd-parse.o: ragel -G2 -o $(BUILD_DIR)/ifchd-parse.c src/ifchd-parse.rl - $(CC) $(CFLAGS) $(NCM_INC) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/ifchd-parse.c + $(CC) $(CFLAGS) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/ifchd-parse.c cfg.o: ragel -G2 -o $(BUILD_DIR)/cfg.c src/cfg.rl - $(CC) $(CFLAGS) $(NCM_INC) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/cfg.c + $(CC) $(CFLAGS) $(NDHC_INC) -c -o $(OBJ_DIR)/src/$@ $(BUILD_DIR)/cfg.c %.o: %.c - $(CC) $(CFLAGS) $(NCM_INC) -c -o $(OBJ_DIR)/$@ $< + $(CC) $(CFLAGS) -c -o $(OBJ_DIR)/$@ $< -ncmlib.a: $(NCM_OBJS) - $(AR) rc $(BUILD_DIR)/$@ $(subst ncmlib/,$(OBJ_DIR)/ncmlib/,$(NCM_OBJS)) - $(RANLIB) $(BUILD_DIR)/$@ - -ndhc: $(NDHC_OBJS) ifchd-parse.o cfg.o - $(CC) $(CFLAGS) $(NCM_INC) -o $(BUILD_DIR)/$@ $(subst src/,$(OBJ_DIR)/src/,$(NDHC_OBJS)) $(BUILD_DIR)/ncmlib.a $(BUILD_DIR)/objs/src/ifchd-parse.o $(BUILD_DIR)/objs/src/cfg.o $(LINK_LIBS) +ndhc: $(NCM_OBJS) $(NDHC_OBJS) ifchd-parse.o cfg.o + $(CC) $(CFLAGS) -o $(BUILD_DIR)/$@ $(subst src/,$(OBJ_DIR)/src/,$(NDHC_OBJS)) $(BUILD_DIR)/objs/src/ifchd-parse.o $(BUILD_DIR)/objs/src/cfg.o $(LINK_LIBS) .PHONY: all clean diff --git a/README.md b/README.md index 810f054..64a2162 100644 --- a/README.md +++ b/README.md @@ -88,15 +88,9 @@ new one. * Linux kernel * GNU Make or CMake * [Ragel 6](https://www.colm.net/open-source/ragel) -* [ncmlib](https://github.com/niklata/ncmlib) ## Installation -Make sure that ncmlib is present in the ndhc source directory: -``` -$ ls -CMakeLists.txt LICENSE Makefile ncmlib README src -``` Compile and install ndhc. * Create a build directory: `mkdir build && cd build` * Create the makefiles: `cmake ..` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 6e263e4..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -project (ndhc DESCRIPTION "dhcp4 client" LANGUAGES C) - -set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.c) -set(RAGEL_CFG_PARSE ${CMAKE_CURRENT_BINARY_DIR}/cfg.c) - -find_program(RAGEL ragel) -add_custom_command( - OUTPUT ${RAGEL_IFCHD_PARSE} - COMMAND ${RAGEL} -G2 -o ${RAGEL_IFCHD_PARSE} ifchd-parse.rl - DEPENDS ifchd-parse.rl - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Compiling Ragel state machine: ifchd-parse.rl" - VERBATIM - ) -set_property(SOURCE ${RAGEL_IFCHD_PARSE} APPEND PROPERTY GENERATED TRUE) -if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set_property(SOURCE ${RAGEL_IFCHD_PARSE} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable") -endif() -add_custom_command( - OUTPUT ${RAGEL_CFG_PARSE} - COMMAND ${RAGEL} -G2 -o ${RAGEL_CFG_PARSE} cfg.rl - DEPENDS cfg.rl - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Compiling Ragel state machine: cfg.rl" - VERBATIM - ) -set_property(SOURCE ${RAGEL_CFG_PARSE} APPEND PROPERTY GENERATED TRUE) -if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set_property(SOURCE ${RAGEL_CFG_PARSE} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-const-variable") -endif() - -add_executable(ndhc ${RAGEL_CFG_PARSE} ${RAGEL_IFCHD_PARSE}) -target_sources(ndhc PRIVATE - "arp.c" - "ifchd.c" - "netlink.c" - "sockd.c" - "dhcp.c" - "ifset.c" - "nl.c" - "state.c" - "duiaid.c" - "leasefile.c" - "options.c" - "sys.c" - "ifchange.c" - "ndhc.c" - "rfkill.c" -) -target_include_directories(ndhc PRIVATE - "${PROJECT_SOURCE_DIR}" - "${PROJECT_SOURCE_DIR}/../ncmlib" - ) -target_link_libraries(ndhc PUBLIC ncmlib) diff --git a/src/cfg.rl b/src/cfg.rl index 1968656..e365a3a 100644 --- a/src/cfg.rl +++ b/src/cfg.rl @@ -12,7 +12,7 @@ #include "ifchd.h" #include "sockd.h" #include "nk/log.h" -#include "nk/privilege.h" +#include "nk/privs.h" #include "nk/copy_cmdarg.h" #include "nk/io.h" diff --git a/src/ifchd-parse.rl b/src/ifchd-parse.rl index 7e604ed..d36a58b 100644 --- a/src/ifchd-parse.rl +++ b/src/ifchd-parse.rl @@ -84,7 +84,7 @@ static int perform_ip4set(const char buf[static 1], size_t len) const char *p = buf; const char *pe = p + len; const char *eof = pe; - const char *arg_start; + const char *arg_start = p; int cs = 0; bool have_ip = false; bool have_subnet = false; @@ -211,7 +211,7 @@ int execute_buffer(const char newbuf[static 1]) size_t init_siz = strlen(buf); const char *p = buf; const char *pe = p + init_siz; - const char *arg_start; + const char *arg_start = p; size_t arg_len = 0; int cs = 0; diff --git a/src/ifchd.c b/src/ifchd.c index 31d314f..1e119a2 100644 --- a/src/ifchd.c +++ b/src/ifchd.c @@ -41,8 +41,7 @@ #include #include #include "nk/log.h" -#include "nk/privilege.h" -#include "nk/signals.h" +#include "nk/privs.h" #include "nk/io.h" #include "ifchd.h" @@ -368,9 +367,8 @@ static void do_ifch_work(void) } } -// If we are requested to update resolv.conf, preopen the fd before -// we drop root privileges, making sure that if we create -// resolv.conf, it will be world-readable. +// If we are requested to update resolv.conf, preopen the fd before we drop +// root, making sure that if we create resolv.conf, it will be world-readable. static void setup_resolv_conf(void) { if (strncmp(resolv_conf_d, "", sizeof resolv_conf_d)) { diff --git a/src/lib/hwrng.c b/src/lib/hwrng.c new file mode 100644 index 0000000..b758a1f --- /dev/null +++ b/src/lib/hwrng.c @@ -0,0 +1,128 @@ +/* hwrng.c - access to system CRNG + * + * Copyright 2013-2018 Nicholas J. Kain + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "nk/hwrng.h" +#include "nk/log.h" +#include "nk/io.h" + +#ifdef NK_USE_GETRANDOM_SYSCALL +#include +#include +static bool nk_getrandom(char *seed, size_t len) +{ + size_t fetched = 0; + while (fetched < len) { + int r = syscall(SYS_getrandom, seed + fetched, len - fetched, 0); + if (r <= 0) { + if (r == 0) { + // Failsafe to guard against infinite loops. + log_warning("%s: getrandom() returned no entropy", __func__); + return false; + } + if (errno == EINTR) + continue; + log_warning("%s: getrandom() failed: %s", __func__, strerror(errno)); + return false; + } + fetched += (size_t)r; + } + return true; +} +#else +static bool nk_getrandom(char *seed, size_t len) +{ + (void)seed; + (void)len; + return false; +} +#endif +static bool nk_get_rnd_clk(char *seed, size_t len) +{ + struct timespec ts; + for (size_t i = 0; i < len; ++i) { + int r = clock_gettime(CLOCK_REALTIME, &ts); + if (r < 0) { + log_warning("%s: Could not call clock_gettime(CLOCK_REALTIME): %s", + __func__, strerror(errno)); + return false; + } + char *p = (char *)&ts.tv_sec; + char *q = (char *)&ts.tv_nsec; + for (size_t j = 0; j < sizeof ts.tv_sec; ++j) + seed[i] ^= p[j]; + for (size_t j = 0; j < sizeof ts.tv_nsec; ++j) + seed[i] ^= q[j]; + // Force some scheduler jitter. + static const struct timespec st = { .tv_sec=0, .tv_nsec=1 }; + nanosleep(&st, (struct timespec *)0); + } + return true; +} + +static bool nk_get_urandom(char *seed, size_t len) +{ + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + log_warning("%s: Could not open /dev/urandom: %s", __func__, + strerror(errno)); + return false; + } + bool ret = true; + int r = safe_read(fd, seed, len); + if (r < 0) { + ret = false; + log_warning("%s: Could not read /dev/urandom: %s", + __func__, strerror(errno)); + } + close(fd); + return ret; +} + +void nk_get_hwrng(void *seed, size_t len) +{ + char *s = (char *)seed; + if (nk_getrandom(s, len)) + return; + if (nk_get_urandom(s, len)) + return; + log_warning("%s: Seeding PRNG via system clock. May be predictable.", + __func__); + if (nk_get_rnd_clk(s, len)) + return; + suicide("%s: All methods to seed PRNG failed. Exiting.", __func__); +} + diff --git a/src/lib/io.c b/src/lib/io.c new file mode 100644 index 0000000..f842421 --- /dev/null +++ b/src/lib/io.c @@ -0,0 +1,131 @@ +/* io.c - light wrappers for POSIX i/o functions + * + * Copyright 2010-2018 Nicholas J. Kain + * 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 +#include +#include +#include "nk/io.h" +#include + +// POSIX says read/write/etc() with len param > SSIZE_MAX is implementation defined. +// So we avoid implementation-defined behavior with the bounding in each safe_* fn. + +/* returns -1 on error, >= 0 and equal to # chars read on success */ +ssize_t safe_read(int fd, char *buf, size_t len) +{ + size_t s = 0; + if (len > SSIZE_MAX) len = SSIZE_MAX; + while (s < len) { + ssize_t r = read(fd, buf + s, len - s); + if (r == 0) + break; + if (r < 0) { + if (errno == EINTR) + continue; + else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0) + return (ssize_t)s; + else + return -1; + } + s += (size_t)r; + } + return (ssize_t)s; +} + +/* returns -1 on error, >= 0 and equal to # chars written on success */ +ssize_t safe_write(int fd, const char *buf, size_t len) +{ + size_t s = 0; + if (len > SSIZE_MAX) len = SSIZE_MAX; + while (s < len) { + ssize_t r = write(fd, buf + s, len - s); + if (r < 0) { + if (errno == EINTR) + continue; + else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0) + return (ssize_t)s; + else + return -1; + } + s += (size_t)r; + } + return (ssize_t)s; +} + +/* returns -1 on error, >= 0 and equal to # chars written on success */ +ssize_t safe_sendto(int fd, const char *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + size_t s = 0; + if (len > SSIZE_MAX) len = SSIZE_MAX; + while (s < len) { + ssize_t r = sendto(fd, buf + s, len - s, flags, dest_addr, addrlen); + if (r < 0) { + if (errno == EINTR) + continue; + else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0) + return (ssize_t)s; + else + return -1; + } + s += (size_t)r; + } + return (ssize_t)s; +} + +ssize_t safe_recv(int fd, char *buf, size_t len, int flags) +{ + size_t s = 0; + if (len > SSIZE_MAX) len = SSIZE_MAX; + while (s < len) { + ssize_t r = recv(fd, buf + s, len - s, flags); + if (r == 0) + break; + if (r < 0) { + if (errno == EINTR) + continue; + else if ((errno == EAGAIN || errno == EWOULDBLOCK) && s > 0) + return (ssize_t)s; + else + return -1; + } + s += (size_t)r; + } + return (ssize_t)s; +} + +ssize_t safe_recvmsg(int fd, struct msghdr *msg, int flags) +{ + ssize_t r; + retry: + r = recvmsg(fd, msg, flags); + if (r < 0 && errno == EINTR) + goto retry; + return r; +} + diff --git a/src/lib/log.c b/src/lib/log.c new file mode 100644 index 0000000..c5aebf9 --- /dev/null +++ b/src/lib/log.c @@ -0,0 +1,82 @@ +/* log.c - simple logging support + * + * Copyright 2003-2018 Nicholas J. Kain + * 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 +#include +#include +#include +#include "nk/log.h" + +/* global logging flags */ +int gflags_quiet = 0; +int gflags_detach = 0; +int gflags_debug = 0; +char *gflags_log_name = 0; + +#define log_syslog(level) do { \ + openlog(gflags_log_name, LOG_PID, LOG_DAEMON); \ + va_start(argp, format); \ + vsyslog(level | LOG_DAEMON, format, argp); \ + va_end(argp); \ + closelog(); } while(0) + +#define log_stdio() do { \ + va_start(argp, format); \ + vfprintf(stderr, format, argp); \ + fprintf(stderr, "\n"); \ + va_end(argp); } while(0) + +__attribute__ ((format (printf, 2, 3))) +void log_line_l(int level, const char format[static 1], ...) +{ + va_list argp; + + if (gflags_quiet) + return; + + if (gflags_detach) + log_syslog(level); + else + log_stdio(); +} + +__attribute__ ((format (printf, 1, 2))) +void __attribute__((noreturn)) suicide(const char format[static 1], ...) +{ + va_list argp; + + if (gflags_detach) + log_syslog(LOG_ERR); + else + log_stdio(); + exit(EXIT_FAILURE); +} + +#undef log_syslog +#undef log_stdio + diff --git a/src/lib/privs.c b/src/lib/privs.c new file mode 100644 index 0000000..aa8c817 --- /dev/null +++ b/src/lib/privs.c @@ -0,0 +1,224 @@ +/* privs.c - uid/gid, chroot, and capability handling + * + * Copyright 2005-2018 Nicholas J. Kain + * 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. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#include +#endif +#include "nk/privs.h" +#include "nk/log.h" + +void nk_set_chroot(const char *chroot_dir) +{ + if (chroot(chroot_dir)) + suicide("%s: chroot('%s') failed: %s", __func__, chroot_dir, + strerror(errno)); + if (chdir("/")) + suicide("%s: chdir('/') failed: %s", __func__, strerror(errno)); +} + +#ifdef NK_USE_CAPABILITY +static size_t nk_get_capability_vinfo(uint32_t version[static 1]) +{ + struct __user_cap_header_struct hdr; + memset(&hdr, 0, sizeof hdr); + if (capget(&hdr, (cap_user_data_t)0) < 0) { + if (errno != EINVAL) + suicide("%s: capget failed: %s", __func__, strerror(errno)); + } + switch (hdr.version) { + case _LINUX_CAPABILITY_VERSION_1: + *version = _LINUX_CAPABILITY_VERSION_1; + return _LINUX_CAPABILITY_U32S_1; + case _LINUX_CAPABILITY_VERSION_2: + *version = _LINUX_CAPABILITY_VERSION_2; + return _LINUX_CAPABILITY_U32S_2; + default: log_warning("%s: unknown capability version %x, using %x", + __func__, *version, _LINUX_CAPABILITY_VERSION_3); + case _LINUX_CAPABILITY_VERSION_3: + *version = _LINUX_CAPABILITY_VERSION_3; + return _LINUX_CAPABILITY_U32S_3; + } +} +static size_t nk_set_capability_prologue(const unsigned char *caps, + size_t caplen, + uint32_t cversion[static 1]) +{ + if (!caps || !caplen) + return 0; + size_t csize = nk_get_capability_vinfo(cversion); + if (prctl(PR_SET_KEEPCAPS, 1)) + suicide("%s: prctl failed: %s", __func__, strerror(errno)); + return csize; +} +static void nk_set_capability_epilogue(const unsigned char *caps, + size_t caplen, uint32_t cversion, + size_t csize) +{ + if (!caps || !caplen) + return; + struct __user_cap_header_struct hdr = { + .version = cversion, + .pid = 0, + }; + struct __user_cap_data_struct data[csize]; + uint32_t mask[csize]; + memset(mask, 0, sizeof mask); + for (size_t i = 0; i < caplen; ++i) { + size_t j = caps[i] / 32; + if (j >= csize) + suicide("%s: caps[%zu] == %u, which is >= %u and out of range", + __func__, caps[i], csize * 32); + mask[j] |= (uint32_t)CAP_TO_MASK(caps[i] - 32 * j); + } + for (size_t i = 0; i < csize; ++i) { + data[i].effective = mask[i]; + data[i].permitted = mask[i]; + data[i].inheritable = 0; + } + if (capset(&hdr, (cap_user_data_t)&data) < 0) + suicide("%s: capset failed: %s", __func__, strerror(errno)); +} +#else +static size_t nk_set_capability_prologue(const unsigned char *caps, + size_t caplen, + uint32_t cversion[static 1]) +{ (void)caps; (void)caplen; (void)cversion; return 0; } +static void nk_set_capability_epilogue(const unsigned char *caps, + size_t caplen, uint32_t cversion, + size_t csize) +{ (void)caps; (void)caplen; (void)cversion; (void)csize; } +#endif + +#ifdef NK_USE_NO_NEW_PRIVS +static void nk_set_no_new_privs(void) +{ + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + suicide("%s: prctl failed: %s", __func__, strerror(errno)); +} +#else +static void nk_set_no_new_privs(void) {} +#endif + +void nk_set_uidgid(uid_t uid, gid_t gid, const unsigned char *caps, + size_t caplen) +{ + uint32_t cversion = 0; + size_t csize = nk_set_capability_prologue(caps, caplen, &cversion); + if (setgroups(1, &gid)) + suicide("%s: setgroups failed: %s", __func__, strerror(errno)); + if (setresgid(gid, gid, gid)) + suicide("%s: setresgid failed: %s", __func__, strerror(errno)); + if (setresuid(uid, uid, uid)) + suicide("%s: setresuid failed: %s", __func__, strerror(errno)); + uid_t ruid, euid, suid; + if (getresuid(&ruid, &euid, &suid)) + suicide("%s: getresuid failed: %s", __func__, strerror(errno)); + if (ruid != uid || euid != uid || suid != uid) + suicide("%s: getresuid failed; the OS or libc is broken", __func__); + gid_t rgid, egid, sgid; + if (getresgid(&rgid, &egid, &sgid)) + suicide("%s: getresgid failed: %s", __func__, strerror(errno)); + if (rgid != gid || egid != gid || sgid != gid) + suicide("%s: getresgid failed; the OS or libc is broken", __func__); + if (uid && setreuid((uid_t)-1, 0) == 0) + suicide("%s: OS or libc broken; able to restore privs after drop", + __func__); + nk_set_capability_epilogue(caps, caplen, cversion, csize); + nk_set_no_new_privs(); +} + +uid_t nk_uidgidbyname(const char *username, uid_t *uid, gid_t *gid) +{ + if (!username) + return (uid_t)-1; + struct passwd *pws = getpwnam(username); + if (!pws) { + for (size_t i = 0; username[i]; ++i) { + if (!isdigit(username[i])) + return (uid_t)-1; + } + char *p; + long lt = strtol(username, &p, 10); + if (errno == ERANGE && (lt == LONG_MIN || lt == LONG_MAX)) + return (uid_t)-1; + if (lt < 0 || lt > (long)UINT_MAX) + return (uid_t)-1; + if (p == username) + return (uid_t)-1; + pws = getpwuid((uid_t)lt); + if (!pws) + return (uid_t)-1; + } + if (gid) + *gid = pws->pw_gid; + if (uid) + *uid = pws->pw_uid; + return (uid_t)0; +} + +gid_t nk_gidbyname(const char *groupname, gid_t *gid) +{ + if (!groupname) + return (gid_t)-1; + struct group *grp = getgrnam(groupname); + if (!grp) { + for (size_t i = 0; groupname[i]; ++i) { + if (!isdigit(groupname[i])) + return (gid_t)-1; + } + char *p; + long lt = strtol(groupname, &p, 10); + if (errno == ERANGE && (lt == LONG_MIN || lt == LONG_MAX)) + return (gid_t)-1; + if (lt < 0 || lt > (long)UINT_MAX) + return (gid_t)-1; + if (p == groupname) + return (gid_t)-1; + grp = getgrgid((gid_t)lt); + if (!grp) + return (gid_t)-1; + } + if (gid) + return grp->gr_gid; + return (gid_t)0; +} + diff --git a/src/lib/random.c b/src/lib/random.c new file mode 100644 index 0000000..46c4fff --- /dev/null +++ b/src/lib/random.c @@ -0,0 +1,62 @@ +/* random.c - non-cryptographic fast PRNG + * + * Copyright 2013-2018 Nicholas J. Kain + * 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 +#include "nk/hwrng.h" +#include "nk/random.h" + +// GJrand64: https://gjrand.sourceforge.net + +void nk_random_init(struct nk_random_state *s) +{ + nk_get_hwrng(s->seed, sizeof(uint64_t) * 2); + s->seed[2] = 2000001; + s->seed[3] = 0; + for (size_t i = 0; i < 14; ++i) nk_random_u64(s); +} + +static inline uint64_t rotl64(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +uint64_t nk_random_u64(struct nk_random_state *s) +{ + s->seed[1] += s->seed[2]; + s->seed[0] = rotl64(s->seed[0], 32); + s->seed[2] ^= s->seed[1]; + s->seed[3] += 0x55aa96a5; + s->seed[0] += s->seed[1]; + s->seed[2] = rotl64(s->seed[2], 23); + s->seed[1] ^= s->seed[0]; + s->seed[0] += s->seed[2]; + s->seed[1] = rotl64(s->seed[1], 19); + s->seed[2] += s->seed[0]; + s->seed[1] += s->seed[3]; + return s->seed[0]; +} + diff --git a/src/ndhc.c b/src/ndhc.c index e6d1f92..be77913 100644 --- a/src/ndhc.c +++ b/src/ndhc.c @@ -48,8 +48,7 @@ #include #include #include "nk/log.h" -#include "nk/privilege.h" -#include "nk/pidfile.h" +#include "nk/privs.h" #include "nk/io.h" #include "nk/copy_cmdarg.h" @@ -153,9 +152,9 @@ void show_usage(void) " -n, --now Exit with failure if lease cannot be\n" " immediately negotiated.\n" " -r, --request=IP IP address to request (default: none)\n" -" -u, --user=USER Change ndhc privileges to this user\n" -" -U, --ifch-user=USER Change ndhc-ifch privileges to this user\n" -" -D, --sockd-user=USER Change ndhc-sockd privileges to this user\n" +" -u, --user=USER ndhc runs as this user\n" +" -U, --ifch-user=USER ndhc-ifch runs as this user\n" +" -D, --sockd-user=USER ndhc-sockd runs as this user\n" " -C, --chroot=DIR Chroot to this directory\n" " -s, --state-dir=DIR State storage dir (default: /etc/ndhc)\n" " -d, --relentless-defense Never back off in defending IP against\n" diff --git a/src/nk/copy_cmdarg.h b/src/nk/copy_cmdarg.h new file mode 100644 index 0000000..0c2ff8d --- /dev/null +++ b/src/nk/copy_cmdarg.h @@ -0,0 +1,18 @@ +#ifndef NCMLIB_COPY_CMDARG_H_ +#define NCMLIB_COPY_CMDARG_H_ + +#include +#include +#include "nk/log.h" + +static inline void copy_cmdarg(char *dest, const char *src, + size_t destlen, const char *argname) +{ + ssize_t olen = snprintf(dest, destlen, "%s", src); + if (olen < 0) + suicide("snprintf failed on %s; your system is broken?", argname); + if ((size_t)olen >= destlen) + suicide("snprintf would truncate %s arg; it's too long", argname); +} + +#endif /* NCMLIB_COPY_CMDARG_H_ */ diff --git a/src/nk/hwrng.h b/src/nk/hwrng.h new file mode 100644 index 0000000..2f5dd19 --- /dev/null +++ b/src/nk/hwrng.h @@ -0,0 +1,37 @@ +/* hwrng.h - access to system CRNG + * + * Copyright 2016 Nicholas J. Kain + * 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. + */ +#ifndef NCMLIB_HWCRNG__ +#define NCMLIB_HWCRNG__ + +#include + +void nk_get_hwrng(void *seed, size_t len); + +#endif + + diff --git a/src/nk/io.h b/src/nk/io.h new file mode 100644 index 0000000..3ecc148 --- /dev/null +++ b/src/nk/io.h @@ -0,0 +1,41 @@ +/* io.h - light wrappers for POSIX i/o functions + * + * Copyright 2010-2015 Nicholas J. Kain + * 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. + */ + +#ifndef NCM_IO_H_ +#define NCM_IO_H_ + +#include + +ssize_t safe_read(int fd, char *buf, size_t len); +ssize_t safe_write(int fd, const char *buf, size_t len); +ssize_t safe_sendto(int fd, const char *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +ssize_t safe_recv(int fd, char *buf, size_t len, int flags); +ssize_t safe_recvmsg(int fd, struct msghdr *msg, int flags); + +#endif /* NCM_IO_H_ */ diff --git a/src/nk/log.h b/src/nk/log.h new file mode 100644 index 0000000..4a3d28d --- /dev/null +++ b/src/nk/log.h @@ -0,0 +1,48 @@ +/* log.h - simple logging support + * + * Copyright 2003-2015 Nicholas J. Kain + * 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. + */ + +#ifndef NCM_LOG_H_ +#define NCM_LOG_H_ + +#include + +extern int gflags_quiet; +extern int gflags_detach; +extern int gflags_debug; +extern char *gflags_log_name; + +#define log_line(...) log_line_l(LOG_INFO, __VA_ARGS__) +#define log_debug(...) if (gflags_debug) log_line_l(LOG_DEBUG, __VA_ARGS__) +#define log_warning(...) log_line_l(LOG_WARNING, __VA_ARGS__) +#define log_error(...) log_line_l(LOG_ERR, __VA_ARGS__) + +void log_line_l(int level, const char *format, ...); +void __attribute__((noreturn)) suicide(const char *format, ...); + +#endif + diff --git a/src/nk/net_checksum.h b/src/nk/net_checksum.h new file mode 100644 index 0000000..46dc55f --- /dev/null +++ b/src/nk/net_checksum.h @@ -0,0 +1,54 @@ +#ifndef NCMLIB_NET_CHECKSUM_H +#define NCMLIB_NET_CHECKSUM_H + +#include + +// When summing ones-complement 16-bit values using a 32-bit unsigned +// representation, fold the carry bits that have spilled into the upper +// 16-bits of the 32-bit unsigned value back into the 16-bit ones-complement +// binary value. +static inline uint16_t net_checksum161c_foldcarry(uint32_t v) +{ + v = (v >> 16) + (v & 0xffff); + v += v >> 16; + return v; +} + +// This function is not suitable for summing buffers that are greater than +// 128k bytes in length: failure case will be incorrect checksums via +// unsigned overflow, which is a defined operation and is safe. This limit +// should not be an issue for IPv4 or IPv6 packet, which are limited to +// at most 64k bytes. +static uint16_t net_checksum161c(const void *buf, size_t size) +{ + uint32_t sum = 0; + int odd = size & 0x01; + size_t i; + size &= ~((size_t)0x01); + size >>= 1; + const uint8_t *b = (const uint8_t *)buf; + for (i = 0; i < size; ++i) { + uint16_t hi = b[i*2]; + uint16_t lo = b[i*2+1]; + sum += ntohs((lo + (hi << 8))); + } + if (odd) { + uint16_t hi = b[i*2]; + uint16_t lo = 0; + sum += ntohs((lo + (hi << 8))); + } + return ~net_checksum161c_foldcarry(sum); +} + +// For two sequences of bytes A and B that return checksums CS(A) and CS(B), +// this function will calculate the checksum CS(AB) of the concatenated value +// AB given the checksums of the individual parts CS(A) and CS(B). +static inline uint16_t net_checksum161c_add(uint16_t a, uint16_t b) +{ + const uint32_t A = a; + const uint32_t B = b; + return ~net_checksum161c_foldcarry((~A & 0xffffu) + (~B & 0xffffu)); +} + +#endif + diff --git a/src/nk/privs.h b/src/nk/privs.h new file mode 100644 index 0000000..4b4da8f --- /dev/null +++ b/src/nk/privs.h @@ -0,0 +1,44 @@ +/* privs.h - uid/gid, chroot, and capability handling + * + * Copyright 2005-2014 Nicholas J. Kain + * 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. + */ + +#ifndef NCM_PRIVS_H_ +#define NCM_PRIVS_H_ + +#include +#ifdef __linux__ +#include +#endif + +void nk_set_chroot(const char *chroot_dir); +void nk_set_uidgid(uid_t uid, gid_t gid, const unsigned char *caps, + size_t caplen); +uid_t nk_uidgidbyname(const char *username, uid_t *uid, gid_t *gid); +gid_t nk_gidbyname(const char *groupname, gid_t *gid); + +#endif + diff --git a/src/nk/random.h b/src/nk/random.h new file mode 100644 index 0000000..43b298e --- /dev/null +++ b/src/nk/random.h @@ -0,0 +1,45 @@ +/* random.h - non-cryptographic fast PRNG + * + * Copyright 2013-2018 Nicholas J. Kain + * 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. + */ +#ifndef NCMLIB_RANDOM__ +#define NCMLIB_RANDOM__ +#include + +struct nk_random_state { + uint64_t seed[4]; +}; + +void nk_random_init(struct nk_random_state *s); +uint64_t nk_random_u64(struct nk_random_state *s); +static inline uint32_t nk_random_u32(struct nk_random_state *s) +{ + // Discard lower bits as they have less linear complexity. + return nk_random_u64(s) >> 32; +} + +#endif + diff --git a/src/sockd.c b/src/sockd.c index a50224a..1861781 100644 --- a/src/sockd.c +++ b/src/sockd.c @@ -50,7 +50,7 @@ #include #include "nk/log.h" #include "nk/io.h" -#include "nk/privilege.h" +#include "nk/privs.h" #include "sockd.h" #include "ndhc-defines.h"