Replace CMake with GNU Make.

There was previously support for both build systems, but ndhc is
undemanding and there is no point in maintaining a complex
CMake build.
This commit is contained in:
Nicholas J. Kain
2022-01-22 18:39:41 -05:00
parent 1055c27bcf
commit 8db8c5589d
54 changed files with 14161 additions and 261 deletions

18
nk/copy_cmdarg.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef NCMLIB_COPY_CMDARG_H_
#define NCMLIB_COPY_CMDARG_H_
#include <stdio.h>
#include <stdlib.h>
#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_ */

128
nk/hwrng.c Normal file
View File

@@ -0,0 +1,128 @@
/* hwrng.c - access to system CRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* 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 <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "nk/hwrng.h"
#include "nk/log.h"
#include "nk/io.h"
#ifdef NK_USE_GETRANDOM_SYSCALL
#include <sys/syscall.h>
#include <linux/random.h>
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_line("%s: getrandom() returned no entropy", __func__);
return false;
}
if (errno == EINTR)
continue;
log_line("%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_line("%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_line("%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_line("%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_line("%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__);
}

37
nk/hwrng.h Normal file
View File

@@ -0,0 +1,37 @@
/* hwrng.h - access to system CRNG
*
* Copyright 2016 Nicholas J. Kain <njkain at gmail dot com>
* 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 <stddef.h>
void nk_get_hwrng(void *seed, size_t len);
#endif

140
nk/io.c Normal file
View File

@@ -0,0 +1,140 @@
/* io.c - light wrappers for POSIX i/o functions
*
* Copyright 2010-2018 Nicholas J. Kain <njkain at gmail dot com>
* 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 <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include "nk/io.h"
#include <limits.h>
// 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;
for (;;) {
r = recvmsg(fd, msg, flags);
if (r >= 0 || errno != EINTR) break;
}
return r;
}
int safe_ftruncate(int fd, off_t length)
{
int r;
for (;;) {
r = ftruncate(fd, length);
if (!r || errno != EINTR) break;
}
return r;
}

42
nk/io.h Normal file
View File

@@ -0,0 +1,42 @@
/* io.h - light wrappers for POSIX i/o functions
*
* Copyright 2010-2015 Nicholas J. Kain <njkain at gmail dot com>
* 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 <sys/socket.h>
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);
int safe_ftruncate(int fd, off_t length);
#endif /* NCM_IO_H_ */

53
nk/log.h Normal file
View File

@@ -0,0 +1,53 @@
/* log.h - simple logging support
*
* Copyright 2003-2020 Nicholas J. Kain <njkain at gmail dot com>
* 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 <stdlib.h>
#include <stdio.h>
#define log_line(...) do { \
dprintf(2, __VA_ARGS__); \
dprintf(2, "\n"); } while (0)
#ifndef NDEBUG
#define log_debug(...) do { \
dprintf(2, __VA_ARGS__); \
dprintf(2, "\n"); } while (0)
#else
#define log_debug(...) do {} while (0)
#endif
#define suicide(...) do { \
dprintf(2, __VA_ARGS__); \
dprintf(2, "\n"); \
exit(EXIT_FAILURE); } while (0)
#endif

57
nk/net_checksum16.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef NCMLIB_NET_CHECKSUM16_H
#define NCMLIB_NET_CHECKSUM16_H
// RFC 1071 is still a good reference.
#include <stdint.h>
// 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_checksum16_foldcarry(uint32_t v)
{
v = (v >> 16) + (v & 0xffff);
v += v >> 16;
return v;
}
// Produces the correct result on little endian in the sense that
// the binary value returned, when stored to memory, will match
// the result on big endian; if the numeric value returned
// must match big endian results, then call ntohs() on the result.
static uint16_t net_checksum16(const void *buf, size_t size)
{
const char *b = (const char *)buf;
const char *bend = b + size;
uint32_t sum = 0, t = 0;
uint8_t z[4] = { 0 };
switch (size & 3) {
case 3: z[2] = (uint8_t)*--bend;
case 2: z[1] = (uint8_t)*--bend;
case 1: z[0] = (uint8_t)*--bend;
default: break;
}
memcpy(&t, z, 4);
sum += t & 0xffffu;
sum += (t >> 16);
for (; b < bend; b += 4) {
memcpy(&t, b, 4);
sum += t & 0xffffu;
sum += (t >> 16);
}
return ~net_checksum16_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_checksum16_add(uint16_t a, uint16_t b)
{
const uint32_t A = a;
const uint32_t B = b;
return ~net_checksum16_foldcarry((~A & 0xffffu) + (~B & 0xffffu));
}
#endif

224
nk/privs.c Normal file
View File

@@ -0,0 +1,224 @@
/* privs.c - uid/gid, chroot, and capability handling
*
* Copyright 2005-2018 Nicholas J. Kain <njkain at gmail dot com>
* 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 <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#ifdef __linux__
#include <sys/capability.h>
#include <sys/prctl.h>
#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)
{
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_line("%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)
{
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] == %d, which is >= %zu and out of range",
__func__, i, 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)
{ (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;
}

44
nk/privs.h Normal file
View File

@@ -0,0 +1,44 @@
/* privs.h - uid/gid, chroot, and capability handling
*
* Copyright 2005-2014 Nicholas J. Kain <njkain at gmail dot com>
* 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 <unistd.h>
#ifdef __linux__
#include <sys/capability.h>
#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

62
nk/random.c Normal file
View File

@@ -0,0 +1,62 @@
/* random.c - non-cryptographic fast PRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* 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 <stdint.h>
#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];
}

45
nk/random.h Normal file
View File

@@ -0,0 +1,45 @@
/* random.h - non-cryptographic fast PRNG
*
* Copyright 2013-2018 Nicholas J. Kain <njkain at gmail dot com>
* 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 <stdint.h>
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