Convert to using shared ncmlib.

This commit is contained in:
Nicholas J. Kain
2010-11-12 05:42:07 -05:00
parent b42eeb8847
commit b882669f85
31 changed files with 149 additions and 716 deletions

@@ -5,8 +5,8 @@ cmake_minimum_required (VERSION 2.6)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX")
#include_directories("${PROJECT_SOURCE_DIR}/ncmlib") include_directories("${PROJECT_SOURCE_DIR}/ncmlib")
#add_subdirectory(ncmlib) add_subdirectory(ncmlib)
add_subdirectory(ifchd) add_subdirectory(ifchd)
add_subdirectory(ndhc) add_subdirectory(ndhc)

@@ -5,13 +5,7 @@ cmake_minimum_required (VERSION 2.6)
set(IFCHD_SRCS set(IFCHD_SRCS
ifchd.c ifchd.c
linux.c linux.c
strlist.c
signals.c
pidfile.c
chroot.c
nstrl.c
log.c
) )
add_executable(ifchd ${IFCHD_SRCS}) add_executable(ifchd ${IFCHD_SRCS})
#target_link_libraries(ifchd ncmlib) target_link_libraries(ifchd ncmlib)

@@ -181,11 +181,11 @@ usually requiring calls to the catch-all ioctl(), and will almost certainly
require platform-dependent code. require platform-dependent code.
Some standard C libraries include a native implementation of strlcpy() and Some standard C libraries include a native implementation of strlcpy() and
strlcat(). Such defines may conflict with my implementations in strlcat(). Such defines may conflict with my implementations in strl.c/strl.h.
nstrl.c/nstrl.h. It is up to the user whether the standard C library It is up to the user whether the standard C library implementations should be
implementations should be used. Note that some machines implement strlcpy() used. Note that some machines implement strlcpy() and strlcat() with
and strlcat() with nonstandard semantics (notably Solaris). On these systems, nonstandard semantics (notably Solaris). On these systems, using the
using the system-provided implementations may lead to security problems. Such system-provided implementations may lead to security problems. Such problems
problems are the fault of the vendor. If you are unsure whether your system is are the fault of the vendor. If you are unsure whether your system is correct
correct or not, I suggest using the implementation that I provide. or not, I suggest using the implementation that I provide.

@@ -1,42 +0,0 @@
/* chroot.c - chroots ncron jobs
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <unistd.h>
#include <stdlib.h>
#include "log.h"
void imprison(char *path)
{
int ret;
if (path == NULL)
return;
ret = chdir(path);
if (ret) {
log_line("Failed to chdir(%s). Not invoking job.", path);
exit(EXIT_FAILURE);
}
ret = chroot(path);
if (ret) {
log_line("Failed to chroot(%s). Not invoking job.", path);
exit(EXIT_FAILURE);
}
}

@@ -1,21 +0,0 @@
/* chroot.h - include file for chroot.c
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NJK_CHROOT_H_
#define NJK_CHROOT_H_ 1
void imprison(char *path);
#endif

@@ -1,5 +1,5 @@
/* ifchd.c - interface change daemon /* ifchd.c - interface change daemon
* Time-stamp: <2010-11-12 04:28:47 njk> * Time-stamp: <2010-11-12 05:14:29 njk>
* *
* (C) 2004 Nicholas J. Kain <njk@aerifal.cx> * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
* *
@@ -41,13 +41,14 @@
#include <getopt.h> #include <getopt.h>
#include "defines.h" #include "defines.h"
#include "malloc.h"
#include "log.h" #include "log.h"
#include "chroot.h" #include "chroot.h"
#include "pidfile.h" #include "pidfile.h"
#include "signals.h" #include "signals.h"
#include "strlist.h" #include "strlist.h"
#include "ifproto.h" #include "ifproto.h"
#include "nstrl.h" #include "strl.h"
#include "linux.h" #include "linux.h"
enum states { enum states {
@@ -117,21 +118,12 @@ static void fix_signals(void) {
hook_signal(SIGTERM, sighandler, 0); hook_signal(SIGTERM, sighandler, 0);
} }
static void suicide(char *errmsg, const char *perrmsg, int status)
{
if (errmsg)
log_line(errmsg);
if (!gflags_detach && perrmsg)
perror(perrmsg);
exit(status);
}
static void die_nulstr(strlist_t *p) static void die_nulstr(strlist_t *p)
{ {
if (!p) if (!p)
suicide("FATAL - NULL passed to die_nulstr\n", NULL, EXIT_FAILURE); suicide("FATAL - NULL passed to die_nulstr");
if (!p->str) if (!p->str)
suicide("FATAL - NULL string in strlist\n", NULL, EXIT_FAILURE); suicide("FATAL - NULL string in strlist");
} }
static void safe_write(int fd, const char *buf, int len) static void safe_write(int fd, const char *buf, int len)
@@ -144,7 +136,7 @@ static void safe_write(int fd, const char *buf, int len)
if (errno == EINTR) if (errno == EINTR)
goto retry; goto retry;
else else
suicide("write returned error\n", NULL, EXIT_FAILURE); suicide("write returned error");
} else { } else {
len -= r; len -= r;
goto retry; goto retry;
@@ -230,7 +222,7 @@ static void parse_list(int idx, char *str, strlist_t **toplist,
n[i] = *p; n[i] = *p;
if (*p == ' ') if (*p == ' ')
++p; ++p;
add_to_strlist(n, &newn); add_to_strlist(&newn, n);
} }
if (newn) { if (newn) {
@@ -352,11 +344,7 @@ static int stream_onto_list(int i)
s = e + 1; s = e + 1;
continue; continue;
} }
curl[i] = malloc(sizeof(strlist_t)); curl[i] = xmalloc(sizeof(strlist_t));
if (curl[i] == NULL)
suicide("FATAL - malloc failed\n", "malloc",
EXIT_FAILURE);
if (head[i] == NULL) { if (head[i] == NULL) {
head[i] = curl[i]; head[i] = curl[i];
@@ -367,11 +355,7 @@ static int stream_onto_list(int i)
if (last[i] != NULL) if (last[i] != NULL)
last[i]->next = curl[i]; last[i]->next = curl[i];
curl[i]->str = malloc(e - s + 1); curl[i]->str = xmalloc(e - s + 1);
if (curl[i]->str == NULL)
suicide("FATAL - malloc failed\n", "malloc",
EXIT_FAILURE);
strlcpy(curl[i]->str, ibuf[i] + s, e - s); strlcpy(curl[i]->str, ibuf[i] + s, e - s);
last[i] = curl[i]; last[i] = curl[i];
@@ -539,24 +523,20 @@ static int get_listen(void)
lsock = socket(PF_UNIX, SOCK_STREAM, 0); lsock = socket(PF_UNIX, SOCK_STREAM, 0);
if (lsock == -1) if (lsock == -1)
suicide("FATAL - failed to create socket\n", suicide("dispatch_work - failed to create socket");
"dispatch_work - socket", EXIT_FAILURE);
fcntl(lsock, F_SETFL, O_NONBLOCK); fcntl(lsock, F_SETFL, O_NONBLOCK);
(void) unlink(COMM_SOCKET_PATH); (void) unlink(COMM_SOCKET_PATH);
ret = bind(lsock, (struct sockaddr *) &lsock_addr, sizeof(lsock_addr)); ret = bind(lsock, (struct sockaddr *) &lsock_addr, sizeof(lsock_addr));
if (ret) if (ret)
suicide("FATAL - failed to bind socket\n", suicide("dispatch_work - failed to bind socket");
"dispatch_work - bind", EXIT_FAILURE);
ret = chmod(COMM_SOCKET_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); ret = chmod(COMM_SOCKET_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (ret) if (ret)
suicide("FATAL - failed to chmod socket\n", suicide("dispatch_work - failed to chmod socket");
"dispatch_work - chmod", EXIT_FAILURE);
ret = listen(lsock, SOCK_QUEUE); ret = listen(lsock, SOCK_QUEUE);
if (ret) if (ret)
suicide("FATAL - failed to listen on socket\n", suicide("dispatch_work - failed to listen on socket");
"dispatch_work - listen", EXIT_FAILURE);
return lsock; return lsock;
} }
@@ -652,8 +632,7 @@ static void dispatch_work(void)
case -1: case -1:
if (pending_exit == 1) if (pending_exit == 1)
return; return;
suicide("FATAL - select returned an error!\n", suicide("dispatch_work - select returned an error!");
"dispatch_work - select", EXIT_FAILURE);
break; break;
} }
@@ -725,7 +704,9 @@ dispatch_work_read_again:
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int c, t, uid = 0, gid = 0; int c, t;
uid_t uid = 0;
gid_t gid = 0;
char pidfile[MAX_PATH_LENGTH] = PID_FILE_DEFAULT; char pidfile[MAX_PATH_LENGTH] = PID_FILE_DEFAULT;
char chrootd[MAX_PATH_LENGTH] = ""; char chrootd[MAX_PATH_LENGTH] = "";
char resolv_conf_d[MAX_PATH_LENGTH] = ""; char resolv_conf_d[MAX_PATH_LENGTH] = "";
@@ -832,8 +813,7 @@ int main(int argc, char** argv) {
uid = (int)pws->pw_uid; uid = (int)pws->pw_uid;
if (!gid) if (!gid)
gid = (int)pws->pw_gid; gid = (int)pws->pw_gid;
} else suicide("FATAL - Invalid uid specified.\n", NULL, } else suicide("FATAL - Invalid uid specified.");
EXIT_FAILURE);
} else } else
uid = t; uid = t;
break; break;
@@ -844,8 +824,8 @@ int main(int argc, char** argv) {
grp = getgrnam(optarg); grp = getgrnam(optarg);
if (grp) { if (grp) {
gid = (int)grp->gr_gid; gid = (int)grp->gr_gid;
} else suicide("FATAL - Invalid gid specified.\n", NULL, } else
EXIT_FAILURE); suicide("FATAL - Invalid gid specified.");
} else } else
gid = t; gid = t;
break; break;
@@ -858,8 +838,8 @@ int main(int argc, char** argv) {
peer_uid = (int)pws->pw_uid; peer_uid = (int)pws->pw_uid;
if (!peer_gid) if (!peer_gid)
peer_gid = (int)pws->pw_gid; peer_gid = (int)pws->pw_gid;
} else suicide("FATAL - Invalid uid specified.\n", NULL, } else
EXIT_FAILURE); suicide("FATAL - Invalid uid specified.");
} else } else
peer_uid = t; peer_uid = t;
break; break;
@@ -870,8 +850,8 @@ int main(int argc, char** argv) {
grp = getgrnam(optarg); grp = getgrnam(optarg);
if (grp) { if (grp) {
peer_gid = (int)grp->gr_gid; peer_gid = (int)grp->gr_gid;
} else suicide("FATAL - Invalid gid specified.\n", NULL, } else
EXIT_FAILURE); suicide("FATAL - Invalid gid specified.");
} else } else
peer_gid = t; peer_gid = t;
break; break;
@@ -889,8 +869,7 @@ int main(int argc, char** argv) {
} }
if (getuid()) if (getuid())
suicide("FATAL - I need root for CAP_NET_ADMIN and chroot!\n", suicide("FATAL - I need root for CAP_NET_ADMIN and chroot!");
NULL, EXIT_FAILURE);
if (gflags_detach) if (gflags_detach)
if (daemon(0,0)) { if (daemon(0,0)) {
@@ -916,18 +895,17 @@ int main(int argc, char** argv) {
resolv_conf_fd = open(resolv_conf_d, O_RDWR | O_CREAT, 644); resolv_conf_fd = open(resolv_conf_d, O_RDWR | O_CREAT, 644);
umask(077); umask(077);
if (resolv_conf_fd == -1) { if (resolv_conf_fd == -1) {
suicide("FATAL - unable to open resolv.conf\n", suicide("FATAL - unable to open resolv.conf");
"main - open", EXIT_FAILURE);
} }
} }
if (!strncmp(chrootd, "", MAX_PATH_LENGTH)) if (!strncmp(chrootd, "", MAX_PATH_LENGTH))
suicide("FATAL - No chroot path specified. Refusing to run.\n", suicide("FATAL - No chroot path specified. Refusing to run.");
NULL, EXIT_FAILURE);
/* Note that failure cases are handled by called fns. */ /* Note that failure cases are handled by called fns. */
imprison(chrootd); imprison(chrootd);
drop_root(uid, gid, "cap_net_admin=ep"); set_cap(uid, gid, "cap_net_admin=ep");
drop_root(uid, gid);
/* Cover our tracks... */ /* Cover our tracks... */
memset(chrootd, '\0', sizeof(chrootd)); memset(chrootd, '\0', sizeof(chrootd));

@@ -1,5 +1,5 @@
/* linux.c - ifchd Linux-specific functions /* linux.c - ifchd Linux-specific functions
* Time-stamp: <2004-06-14 njk> * Time-stamp: <2010-11-12 05:14:52 njk>
* *
* (C) 2004 Nicholas J. Kain <njk@aerifal.cx> * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
* *
@@ -44,7 +44,7 @@
#include "log.h" #include "log.h"
#include "strlist.h" #include "strlist.h"
#include "ifproto.h" #include "ifproto.h"
#include "nstrl.h" #include "strl.h"
/* Symbolic name of the interface associated with a connection. */ /* Symbolic name of the interface associated with a connection. */
static char ifnam[SOCK_QUEUE][IFNAMSIZ]; static char ifnam[SOCK_QUEUE][IFNAMSIZ];
@@ -70,7 +70,7 @@ void add_permitted_if(char *s)
{ {
if (!s) if (!s)
return; return;
add_to_strlist(s, &okif); add_to_strlist(&okif, s);
} }
/* Checks if changes are permitted to a given interface. 1 == allowed */ /* Checks if changes are permitted to a given interface. 1 == allowed */
@@ -334,7 +334,7 @@ void perform_broadcast(int idx, char *str)
close(fd); close(fd);
} }
static void set_cap(uid_t uid, gid_t gid, char *captxt) void set_cap(uid_t uid, gid_t gid, char *captxt)
{ {
cap_t caps; cap_t caps;
@@ -371,24 +371,3 @@ static void set_cap(uid_t uid, gid_t gid, char *captxt)
cap_free(caps); cap_free(caps);
} }
void drop_root(uid_t uid, gid_t gid, char *captxt)
{
if (!captxt) {
log_line("FATAL - drop_root: captxt == NULL\n");
exit(EXIT_FAILURE);
}
if (uid == 0 || gid == 0) {
log_line("FATAL - drop_root: attempt to drop root to root?\n");
exit(EXIT_FAILURE);
}
set_cap(uid, gid, captxt);
if (setregid(gid, gid) == -1 || setreuid(uid, uid) == -1) {
log_line("FATAL - drop_root: failed to drop root!\n");
exit(EXIT_FAILURE);
}
}

@@ -1,5 +1,5 @@
/* linux.h - ifchd Linux-specific functions include /* linux.h - ifchd Linux-specific functions include
* Time-stamp: <2004-06-13 njk> * Time-stamp: <2010-11-12 04:59:01 njk>
* *
* (C) 2004 Nicholas J. Kain <njk@aerifal.cx> * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
* *
@@ -31,6 +31,6 @@ void perform_subnet(int idx, char *str);
void perform_router(int idx, char *str); void perform_router(int idx, char *str);
void perform_mtu(int idx, char *str); void perform_mtu(int idx, char *str);
void perform_broadcast(int idx, char *str); void perform_broadcast(int idx, char *str);
void drop_root(uid_t uid, gid_t gid, char *captxt); void set_cap(uid_t uid, gid_t gid, char *captxt);
#endif #endif

@@ -1,46 +0,0 @@
/* log.c - simple logging support for ncron
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdio.h>
#include <strings.h>
#include <syslog.h>
#include <stdarg.h>
#include "defines.h"
/* global logging flags */
int gflags_quiet = 0;
int gflags_detach = 1;
void log_line(char *format, ...) {
va_list argp;
if (format == NULL || gflags_quiet)
return;
if (gflags_detach) {
openlog("ifchd", LOG_PID, LOG_DAEMON);
va_start(argp, format);
vsyslog(LOG_ERR | LOG_DAEMON, format, argp);
va_end(argp);
closelog();
} else {
va_start(argp, format);
vfprintf(stderr, format, argp);
va_end(argp);
}
closelog();
}

@@ -1,26 +0,0 @@
/* log.h - simple logging support for ncron
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NJK_LOG_H_
#define NJK_LOG_H_ 1
extern int gflags_quiet;
extern int gflags_detach;
void log_line(char* format, ...);
#endif

@@ -1,46 +0,0 @@
/* nstrl.c - strlcpy/strlcat implementation
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <unistd.h>
#ifndef HAVE_STRLCPY
size_t strlcpy (char *dest, char *src, size_t size)
{
register char *d = dest, *s = src;
for (; *s != '\0' && size > 0; size--, d++, s++)
*d = *s;
*d = '\0';
return (d - dest) + (s - src);
}
size_t strlcat (char *dest, char *src, size_t size)
{
register char *d = dest, *s = src;
for (; size > 0 && *d != '\0'; size--, d++);
for (; *s != '\0' && size > 0; size--, d++, s++)
*d = *s;
*d = '\0';
return (d - dest) + (s - src);
}
#endif

@@ -1,23 +0,0 @@
/* nstrl.h - header file for strlcpy/strlcat implementation
(C) 2003 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NJK_HAVE_STRL_
#define NJK_HAVE_STRL_ 1
size_t strlcpy (char *dest, char *src, size_t size);
size_t strlcat (char *dest, char *src, size_t size);
#endif

@@ -1,45 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include "defines.h"
#include "log.h"
void write_pid(char *file) {
FILE *f;
char buf[MAXLINE];
if (!file)
return;
f = fopen(file, "w");
if (f == NULL) {
log_line("FATAL - failed to open pid file \"%s\"!\n", file);
exit(EXIT_FAILURE);
}
snprintf(buf, sizeof buf, "%i", (unsigned int)getpid());
fwrite(buf, sizeof (char), strlen(buf), f);
if (fclose(f) != 0) {
log_line("FATAL - failed to close pid file \"%s\"!\n", file);
exit(EXIT_FAILURE);
}
}
/* Return 0 on success, -1 on failure. */
int file_exists(char *file, char *mode) {
FILE *f;
if (file == NULL || mode == NULL)
return -1;
f = fopen(file, mode);
if (f == NULL)
return -1;
fclose(f);
return 0;
}

@@ -1,6 +0,0 @@
#ifndef NJK_PIDFILE_H_
#define NJK_PIDFILE_H_ 1
void write_pid(char *file);
int file_exists(char *file, char *mode);
#endif

@@ -1,46 +0,0 @@
/* signals.c - abstracts signal handling
(C) 2004 Nicholas J. Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include "log.h"
void hook_signal(int signum, void (*fn)(int), int flags) {
struct sigaction new_action;
new_action.sa_handler = fn;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = flags;
if (sigaction(signum, &new_action, NULL)) {
log_line("FATAL - failed to hook signal %i\n", signum);
exit(EXIT_FAILURE);
}
}
void disable_signal(int signum) {
struct sigaction new_action;
new_action.sa_handler = SIG_IGN;
sigemptyset(&new_action.sa_mask);
if (sigaction(signum, &new_action, NULL)) {
log_line("FATAL - failed to ignore signal %i\n", signum);
exit(EXIT_FAILURE);
}
}

@@ -1,6 +0,0 @@
#ifndef NJK_SIGNALS_H_
#define NJK_SIGNALS_H_ 1
void hook_signal(int signum, void (*fn)(int), int flags);
void disable_signal(int signum);
#endif

@@ -1,71 +0,0 @@
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include "nstrl.h"
#include "strlist.h"
void add_to_strlist(char *name, strlist_t **list)
{
strlist_t *item, *t;
char *s;
unsigned int len;
if (!list || !name)
return;
len = strlen(name);
if (!len)
return;
s = malloc(len + 1);
if (!s)
return;
strlcpy(s, name, len + 1);
item = malloc(sizeof (strlist_t));
if (!item)
goto out0;
item->str = s;
item->next = NULL;
if (!*list) {
*list = item;
return;
}
for (t = *list; t->next; t = t->next)
if (!t->next) {
t->next = item;
return;
}
free(item); /* should be impossible, but hey */
out0:
free(s);
return;
}
void free_strlist(strlist_t *head)
{
strlist_t *p = head, *q = NULL;
while (p != NULL) {
free(p->str);
q = p;
p = q->next;
free(q);
}
}
void free_stritem(strlist_t **p)
{
strlist_t *q;
if (!p || !*p)
return;
q = (*p)->next;
free((*p)->str);
free(*p);
*p = q;
}

@@ -1,14 +0,0 @@
#ifndef NJK_STRLIST_H_
#define NJK_STRLIST_H_ 1
typedef struct
{
char *str;
void *next;
} strlist_t;
void add_to_strlist(char *name, strlist_t **list);
void free_strlist(strlist_t *head);
void free_stritem(strlist_t **p);
#endif

@@ -3,16 +3,14 @@ project (ndhc)
cmake_minimum_required (VERSION 2.6) cmake_minimum_required (VERSION 2.6)
set(NDHC_SRCS set(NDHC_SRCS
nstrl.c
log.c
options.c options.c
socket.c socket.c
packet.c packet.c
rootcap.c
script.c script.c
clientpacket.c clientpacket.c
rootcap.c
dhcpc.c dhcpc.c
) )
add_executable(ndhc ${NDHC_SRCS}) add_executable(ndhc ${NDHC_SRCS})
#target_link_libraries(ndhc ncmlib) target_link_libraries(ndhc ncmlib)

@@ -50,8 +50,8 @@ unsigned long random_xid(void)
fd = open("/dev/urandom", O_RDONLY); fd = open("/dev/urandom", O_RDONLY);
if (fd == -1 || read(fd, &seed, sizeof(seed)) < 0) { if (fd == -1 || read(fd, &seed, sizeof(seed)) < 0) {
log_line(LOG_WARNING, "Could not load seed from /dev/urandom: %s\n", log_warning("Could not load seed from /dev/urandom: %s",
strerror(errno)); strerror(errno));
seed = time(0); seed = time(0);
} }
if (fd != -1) if (fd != -1)
@@ -111,7 +111,7 @@ int send_discover(unsigned long xid, unsigned long requested)
add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
add_requests(&packet); add_requests(&packet);
log_line(LOG_DEBUG, "Sending discover...\n"); log_line("Sending discover...");
return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
} }
@@ -132,7 +132,7 @@ int send_selecting(unsigned long xid, unsigned long server,
add_requests(&packet); add_requests(&packet);
addr.s_addr = requested; addr.s_addr = requested;
log_line(LOG_DEBUG, "Sending select for %s...\n", inet_ntoa(addr)); log_line("Sending select for %s...", inet_ntoa(addr));
return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
} }
@@ -149,7 +149,7 @@ int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr)
packet.ciaddr = ciaddr; packet.ciaddr = ciaddr;
add_requests(&packet); add_requests(&packet);
log_line(LOG_DEBUG, "Sending renew...\n"); log_line("Sending renew...");
if (server) if (server)
ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
else else
@@ -171,7 +171,7 @@ int send_release(unsigned long server, unsigned long ciaddr)
add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr);
add_simple_option(packet.options, DHCP_SERVER_ID, server); add_simple_option(packet.options, DHCP_SERVER_ID, server);
log_line(LOG_DEBUG, "Sending release...\n"); log_line("Sending release...");
return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
} }
@@ -188,18 +188,18 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
memset(&packet, 0, sizeof(struct udp_dhcp_packet)); memset(&packet, 0, sizeof(struct udp_dhcp_packet));
bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet)); bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
if (bytes < 0) { if (bytes < 0) {
debug(LOG_INFO, "couldn't read on raw listening socket -- ignoring\n"); log_line("couldn't read on raw listening socket -- ignoring");
usleep(500000); /* possible down interface, looping condition */ usleep(500000); /* possible down interface, looping condition */
return -1; return -1;
} }
if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) { if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
debug(LOG_INFO, "message too short, ignoring\n"); log_line("message too short, ignoring");
return -2; return -2;
} }
if (bytes < ntohs(packet.ip.tot_len)) { if (bytes < ntohs(packet.ip.tot_len)) {
debug(LOG_INFO, "Truncated packet\n"); log_line("Truncated packet");
return -2; return -2;
} }
@@ -214,7 +214,7 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
|| packet.udp.dest != htons(CLIENT_PORT) || packet.udp.dest != htons(CLIENT_PORT)
|| bytes > (int)sizeof(struct udp_dhcp_packet) || bytes > (int)sizeof(struct udp_dhcp_packet)
|| ntohs(packet.udp.len) != (short)(bytes - sizeof(packet.ip))) { || ntohs(packet.udp.len) != (short)(bytes - sizeof(packet.ip))) {
debug(LOG_INFO, "unrelated/bogus packet\n"); log_line("unrelated/bogus packet");
return -2; return -2;
} }
@@ -222,7 +222,7 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
check = packet.ip.check; check = packet.ip.check;
packet.ip.check = 0; packet.ip.check = 0;
if (check != checksum(&(packet.ip), sizeof(packet.ip))) { if (check != checksum(&(packet.ip), sizeof(packet.ip))) {
debug(LOG_INFO, "bad IP header checksum, ignoring\n"); log_line("bad IP header checksum, ignoring");
return -1; return -1;
} }
@@ -238,7 +238,7 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
packet.ip.daddr = dest; packet.ip.daddr = dest;
packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */ packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
if (check && check != checksum(&packet, bytes)) { if (check && check != checksum(&packet, bytes)) {
debug(LOG_ERR, "packet with bad UDP checksum received, ignoring\n"); log_error("packet with bad UDP checksum received, ignoring");
return -2; return -2;
} }
@@ -246,10 +246,10 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
bytes - (sizeof(packet.ip) + sizeof(packet.udp))); bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
if (ntohl(payload->cookie) != DHCP_MAGIC) { if (ntohl(payload->cookie) != DHCP_MAGIC) {
log_line(LOG_ERR, "received bogus message (bad magic) -- ignoring\n"); log_error("received bogus message (bad magic) -- ignoring");
return -2; return -2;
} }
debug(LOG_INFO, "oooooh!!! got some!\n"); log_line("oooooh!!! got some!");
return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
} }

@@ -49,8 +49,9 @@
#include "script.h" #include "script.h"
#include "socket.h" #include "socket.h"
#include "log.h" #include "log.h"
#include "chroot.h"
#include "rootcap.h" #include "rootcap.h"
#include "nstrl.h" #include "strl.h"
#define VERSION "1.0" #define VERSION "1.0"
@@ -104,8 +105,8 @@ static void show_usage(void)
/* just a little helper */ /* just a little helper */
static void change_mode(int new_mode) static void change_mode(int new_mode)
{ {
debug(LOG_INFO, "entering %s listen mode", log_line("entering %s listen mode",
new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
close(fd); close(fd);
fd = -1; fd = -1;
listen_mode = new_mode; listen_mode = new_mode;
@@ -114,7 +115,7 @@ static void change_mode(int new_mode)
/* perform a renew */ /* perform a renew */
static void perform_renew(void) static void perform_renew(void)
{ {
log_line(LOG_INFO, "Performing a DHCP renew...\n"); log_line("Performing a DHCP renew...");
switch (state) { switch (state) {
case BOUND: case BOUND:
change_mode(LISTEN_KERNEL); change_mode(LISTEN_KERNEL);
@@ -154,12 +155,12 @@ static void perform_release(void)
temp_addr.s_addr = server_addr; temp_addr.s_addr = server_addr;
snprintf(buf, sizeof buf, "%s", inet_ntoa(temp_addr)); snprintf(buf, sizeof buf, "%s", inet_ntoa(temp_addr));
temp_addr.s_addr = requested_ip; temp_addr.s_addr = requested_ip;
log_line(LOG_INFO, "Unicasting a release of %s to %s.\n", log_line("Unicasting a release of %s to %s.",
inet_ntoa(temp_addr), buf); inet_ntoa(temp_addr), buf);
send_release(server_addr, requested_ip); /* unicast */ send_release(server_addr, requested_ip); /* unicast */
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
} }
log_line(LOG_INFO, "Entering released state.\n"); log_line("Entering released state.");
change_mode(LISTEN_NONE); change_mode(LISTEN_NONE);
state = RELEASED; state = RELEASED;
@@ -208,10 +209,10 @@ static void handle_timeout(void)
packet_num++; packet_num++;
} else { } else {
if (client_config.background_if_no_lease) { if (client_config.background_if_no_lease) {
log_line(LOG_INFO, "No lease, going to background.\n"); log_line("No lease, going to background.");
background(); background();
} else if (client_config.abort_if_no_lease) { } else if (client_config.abort_if_no_lease) {
log_line(LOG_INFO, "No lease, failing.\n"); log_line("No lease, failing.");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* wait to try again */ /* wait to try again */
@@ -245,7 +246,7 @@ static void handle_timeout(void)
/* Lease is starting to run out, time to enter renewing state */ /* Lease is starting to run out, time to enter renewing state */
state = RENEWING; state = RENEWING;
change_mode(LISTEN_KERNEL); change_mode(LISTEN_KERNEL);
debug(LOG_INFO, "Entering renew state.\n"); log_line("Entering renew state.");
/* fall right through */ /* fall right through */
case RENEWING: case RENEWING:
/* Either set a new T1, or enter REBINDING state */ /* Either set a new T1, or enter REBINDING state */
@@ -253,7 +254,7 @@ static void handle_timeout(void)
/* timed out, enter rebinding state */ /* timed out, enter rebinding state */
state = REBINDING; state = REBINDING;
timeout = now + (t2 - t1); timeout = now + (t2 - t1);
debug(LOG_INFO, "Entering rebinding state.\n"); log_line("Entering rebinding state.");
} else { } else {
/* send a request packet */ /* send a request packet */
send_renew(xid, server_addr, requested_ip); /* unicast */ send_renew(xid, server_addr, requested_ip); /* unicast */
@@ -267,7 +268,7 @@ static void handle_timeout(void)
if ((lease - t2) <= (lease / 14400 + 1)) { if ((lease - t2) <= (lease / 14400 + 1)) {
/* timed out, enter init state */ /* timed out, enter init state */
state = INIT_SELECTING; state = INIT_SELECTING;
log_line(LOG_INFO, "Lease lost, entering init state.\n"); log_line("Lease lost, entering init state.");
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
timeout = now; timeout = now;
packet_num = 0; packet_num = 0;
@@ -295,7 +296,7 @@ static void handle_packet(void)
struct in_addr temp_addr; struct in_addr temp_addr;
struct dhcpMessage packet; struct dhcpMessage packet;
debug(LOG_INFO, "got a packet\n"); log_line("got a packet");
if (listen_mode == LISTEN_KERNEL) if (listen_mode == LISTEN_KERNEL)
len = get_packet(&packet, fd); len = get_packet(&packet, fd);
@@ -303,8 +304,8 @@ static void handle_packet(void)
len = get_raw_packet(&packet, fd); len = get_raw_packet(&packet, fd);
if (len == -1 && errno != EINTR) { if (len == -1 && errno != EINTR) {
debug(LOG_INFO, "error on read, %s, reopening socket.\n", log_error("error on read, %s, reopening socket.",
strerror(errno)); strerror(errno));
change_mode(listen_mode); /* just close and reopen */ change_mode(listen_mode); /* just close and reopen */
} }
@@ -312,13 +313,13 @@ static void handle_packet(void)
return; return;
if (packet.xid != xid) { if (packet.xid != xid) {
debug(LOG_INFO, "Ignoring XID %lx (our xid is %lx).\n", log_line("Ignoring XID %lx (our xid is %lx).",
(unsigned long) packet.xid, xid); (unsigned long) packet.xid, xid);
return; return;
} }
if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
debug(LOG_ERR, "couldnt get option from packet -- ignoring\n"); log_line("couldnt get option from packet -- ignoring");
return; return;
} }
@@ -336,7 +337,7 @@ static void handle_packet(void)
timeout = now; timeout = now;
packet_num = 0; packet_num = 0;
} else { } else {
debug(LOG_ERR, "No server ID in message\n"); log_line("No server ID in message");
} }
} }
break; break;
@@ -346,8 +347,7 @@ static void handle_packet(void)
case REBINDING: case REBINDING:
if (*message == DHCPACK) { if (*message == DHCPACK) {
if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
log_line(LOG_ERR, log_line("No lease time received, assuming 1h.");
"No lease time received, assuming 1h.\n");
lease = 60 * 60; lease = 60 * 60;
} else { } else {
memcpy(&lease, temp, 4); memcpy(&lease, temp, 4);
@@ -360,9 +360,8 @@ static void handle_packet(void)
/* little fixed point for n * .875 */ /* little fixed point for n * .875 */
t2 = (lease * 0x7) >> 3; t2 = (lease * 0x7) >> 3;
temp_addr.s_addr = packet.yiaddr; temp_addr.s_addr = packet.yiaddr;
log_line(LOG_INFO, log_line("Lease of %s obtained, lease time %ld.",
"Lease of %s obtained, lease time %ld.\n", inet_ntoa(temp_addr), lease);
inet_ntoa(temp_addr), lease);
start = now; start = now;
timeout = t1 + start; timeout = t1 + start;
requested_ip = packet.yiaddr; requested_ip = packet.yiaddr;
@@ -379,7 +378,7 @@ static void handle_packet(void)
} else if (*message == DHCPNAK) { } else if (*message == DHCPNAK) {
/* return to init state */ /* return to init state */
log_line(LOG_INFO, "Received DHCP NAK.\n"); log_line("Received DHCP NAK.");
run_script(&packet, SCRIPT_NAK); run_script(&packet, SCRIPT_NAK);
if (state != REQUESTING) if (state != REQUESTING)
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
@@ -410,7 +409,7 @@ static int do_work(void)
if (pending_release) if (pending_release)
perform_release(); perform_release();
if (pending_exit) { if (pending_exit) {
log_line(LOG_INFO, "Received SIGTERM. Exiting gracefully.\n"); log_line("Received SIGTERM. Exiting gracefully.");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@@ -425,8 +424,8 @@ static int do_work(void)
fd = raw_socket(client_config.ifindex); fd = raw_socket(client_config.ifindex);
if (fd < 0) { if (fd < 0) {
log_line(LOG_ERR, "FATAL: couldn't listen on socket: %s.\n", log_error("FATAL: couldn't listen on socket: %s.",
strerror(errno)); strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -439,19 +438,17 @@ static int do_work(void)
FD_ZERO(&rfds); FD_ZERO(&rfds);
if (fd >= 0) if (fd >= 0)
FD_SET(fd, &rfds); FD_SET(fd, &rfds);
debug(LOG_INFO, "Waiting on select...\n");
if (select(fd + 1, &rfds, NULL, NULL, &tv) == -1) { if (select(fd + 1, &rfds, NULL, NULL, &tv) == -1) {
switch (errno) { switch (errno) {
case EBADF: case EBADF:
fd = -1; fd = -1;
default: default:
debug(LOG_ERR, "Error: \"%s\" on select!\n", log_error("Error: \"%s\" on select!",
strerror(errno)); strerror(errno));
case EINTR: /* Signal received, go back to top. */ case EINTR: /* Signal received, go back to top. */
continue; continue;
} }
} }
debug(LOG_INFO, "select suceeded\n");
if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds))
handle_packet(); handle_packet();
@@ -553,7 +550,7 @@ int main(int argc, char **argv)
} }
} }
log_line(LOG_INFO, "ndhc client " VERSION " started.\n"); log_line("ndhc client " VERSION " started.");
if (read_interface(client_config.interface, &client_config.ifindex, if (read_interface(client_config.interface, &client_config.ifindex,
NULL, client_config.arp) < 0) NULL, client_config.arp) < 0)
@@ -581,9 +578,10 @@ int main(int argc, char **argv)
printf("Failed to chroot(%s)!\n", chroot_dir); printf("Failed to chroot(%s)!\n", chroot_dir);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
drop_root(uid, gid, set_cap(uid, gid,
"cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep"); "cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep");
drop_root(uid, gid);
state = INIT_SELECTING; state = INIT_SELECTING;
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);

@@ -1,20 +0,0 @@
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <syslog.h>
void log_line(int level, char *format, ...) {
va_list argp;
if (format == NULL) return;
va_start(argp, format);
vfprintf(stderr, format, argp);
va_end(argp);
openlog("ndhc", 0, 0);
va_start(argp, format);
vsyslog(level, format, argp);
va_end(argp);
closelog();
}

@@ -1,11 +0,0 @@
#ifndef H_LOG_H__
#define H_LOG_H__
#include <syslog.h>
void log_line(int level, char *format, ...);
#ifdef DEBUG
#define debug log_line
#else
#define debug(...)
#endif
#endif

@@ -1,48 +0,0 @@
/* nstrl.c - strlcpy/strlcat implementation
Time-stamp: <2003-05-28 02:35:13 njk>
(C) 2003 Nicholas Jay Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <unistd.h>
#ifndef HAVE_STRLCPY
size_t strlcpy (char *dest, char *src, size_t size)
{
register char *d = dest, *s = src;
for (; *s != '\0' && size > 0; size--, d++, s++)
*d = *s;
*d = '\0';
return (d - dest) + (s - src);
}
size_t strlcat (char *dest, char *src, size_t size)
{
register char *d = dest, *s = src;
for (; size > 0 && *d != '\0'; size--, d++);
for (; *s != '\0' && size > 0; size--, d++, s++)
*d = *s;
*d = '\0';
return (d - dest) + (s - src);
}
#endif

@@ -1,25 +0,0 @@
/* nstrl.h - header file for strlcpy/strlcat implementation
Time-stamp: <2003-05-28 02:34:47 njk>
(C) 2003 Nicholas Jay Kain <njk@aerifal.cx>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NJK_HAVE_STRL_
size_t strlcpy (char *dest, char *src, size_t size);
size_t strlcat (char *dest, char *src, size_t size);
#endif
#define NJK_HAVE_STRL_ 1

@@ -70,12 +70,12 @@ unsigned char *get_option(struct dhcpMessage *packet, int code)
optionptr = packet->options; optionptr = packet->options;
while (!done) { while (!done) {
if (i >= length) { if (i >= length) {
log_line(LOG_WARNING, "bogus packet, option fields too long.\n"); log_warning("bogus packet, option fields too long.");
return NULL; return NULL;
} }
if (optionptr[i + OPT_CODE] == code) { if (optionptr[i + OPT_CODE] == code) {
if (i + 1 + optionptr[i + OPT_LEN] >= length) { if (i + 1 + optionptr[i + OPT_LEN] >= length) {
log_line(LOG_WARNING, "bogus packet, option fields too long.\n"); log_warning("bogus packet, option fields too long.");
return NULL; return NULL;
} }
return optionptr + i + 2; return optionptr + i + 2;
@@ -86,8 +86,7 @@ unsigned char *get_option(struct dhcpMessage *packet, int code)
break; break;
case DHCP_OPTION_OVER: case DHCP_OPTION_OVER:
if (i + 1 + optionptr[i + OPT_LEN] >= length) { if (i + 1 + optionptr[i + OPT_LEN] >= length) {
log_line(LOG_WARNING, log_warning("bogus packet, option fields too long.");
"bogus packet, option fields too long.\n");
return NULL; return NULL;
} }
over = optionptr[i + 3]; over = optionptr[i + 3];
@@ -137,11 +136,11 @@ int add_option_string(unsigned char *optionptr, unsigned char *string)
/* end position + string length + option code/length + end option */ /* end position + string length + option code/length + end option */
if (end + string[OPT_LEN] + 2 + 1 >= 308) { if (end + string[OPT_LEN] + 2 + 1 >= 308) {
log_line(LOG_ERR, "Option 0x%02x did not fit into the packet!\n", log_error("Option 0x%02x did not fit into the packet!",
string[OPT_CODE]); string[OPT_CODE]);
return 0; return 0;
} }
debug(LOG_INFO, "adding option 0x%02x\n", string[OPT_CODE]); log_line("adding option 0x%02x", string[OPT_CODE]);
memcpy(optionptr + end, string, string[OPT_LEN] + 2); memcpy(optionptr + end, string, string[OPT_LEN] + 2);
optionptr[end + string[OPT_LEN] + 2] = DHCP_END; optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
return string[OPT_LEN] + 2; return string[OPT_LEN] + 2;
@@ -162,7 +161,7 @@ int add_simple_option(unsigned char *optionptr, unsigned char code,
option[OPT_LEN] = (unsigned char)length; option[OPT_LEN] = (unsigned char)length;
if (!length) { if (!length) {
debug(LOG_ERR, "Could not add option 0x%02x\n", code); log_error("Could not add option 0x%02x", code);
return 0; return 0;
} else if (length == 1) { } else if (length == 1) {
uint8_t t = (uint8_t)data; uint8_t t = (uint8_t)data;
@@ -196,8 +195,8 @@ void attach_option(struct option_set **opt_list, struct dhcp_option *option,
/* add it to an existing option */ /* add it to an existing option */
if ((existing = find_option(*opt_list, option->code))) { if ((existing = find_option(*opt_list, option->code))) {
debug(LOG_INFO, "Attaching option %s to existing member of list\n", log_line("Attaching option %s to existing member of list",
option->name); option->name);
if (option->flags & OPTION_LIST) { if (option->flags & OPTION_LIST) {
if (existing->data[OPT_LEN] + length <= 255) { if (existing->data[OPT_LEN] + length <= 255) {
existing->data = realloc(existing->data, existing->data = realloc(existing->data,
@@ -209,7 +208,7 @@ void attach_option(struct option_set **opt_list, struct dhcp_option *option,
in the future */ in the future */
} /* else, ignore the new data */ } /* else, ignore the new data */
} else { } else {
debug(LOG_INFO, "Attaching option %s to list\n", option->name); log_line("Attaching option %s to list", option->name);
/* make a new option */ /* make a new option */
new = malloc(sizeof(struct option_set)); new = malloc(sizeof(struct option_set));

@@ -51,15 +51,15 @@ int get_packet(struct dhcpMessage *packet, int fd)
memset(packet, 0, sizeof(struct dhcpMessage)); memset(packet, 0, sizeof(struct dhcpMessage));
bytes = read(fd, packet, sizeof(struct dhcpMessage)); bytes = read(fd, packet, sizeof(struct dhcpMessage));
if (bytes < 0) { if (bytes < 0) {
debug(LOG_INFO, "couldn't read on listening socket, ignoring\n"); log_line("couldn't read on listening socket, ignoring");
return -1; return -1;
} }
if (ntohl(packet->cookie) != DHCP_MAGIC) { if (ntohl(packet->cookie) != DHCP_MAGIC) {
log_line(LOG_ERR, "received bogus message, ignoring.\n"); log_error("received bogus message, ignoring.");
return -2; return -2;
} }
debug(LOG_INFO, "Received a packet\n"); log_line("Received a packet");
if (packet->op == BOOTREQUEST if (packet->op == BOOTREQUEST
&& (vendor = get_option(packet, DHCP_VENDOR))) && (vendor = get_option(packet, DHCP_VENDOR)))
@@ -69,7 +69,7 @@ int get_packet(struct dhcpMessage *packet, int fd)
&& !strncmp((char *)vendor, broken_vendors[i], && !strncmp((char *)vendor, broken_vendors[i],
vendor[OPT_LEN - 2])) vendor[OPT_LEN - 2]))
{ {
debug(LOG_INFO, "broken client (%s), forcing broadcast\n", log_line("broken client (%s), forcing broadcast",
broken_vendors[i]); broken_vendors[i]);
packet->flags |= htons(BROADCAST_FLAG); packet->flags |= htons(BROADCAST_FLAG);
} }
@@ -118,7 +118,7 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
struct udp_dhcp_packet packet; struct udp_dhcp_packet packet;
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
debug(LOG_ERR, "socket call failed: %s\n", strerror(errno)); log_error("socket call failed: %s", strerror(errno));
goto out; goto out;
} }
@@ -131,7 +131,7 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
dest.sll_halen = 6; dest.sll_halen = 6;
memcpy(dest.sll_addr, dest_arp, 6); memcpy(dest.sll_addr, dest_arp, 6);
if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
debug(LOG_ERR, "bind call failed: %s\n", strerror(errno)); log_error("bind call failed: %s", strerror(errno));
goto out_fd; goto out_fd;
} }
@@ -155,8 +155,8 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0,
(struct sockaddr *)&dest, sizeof dest); (struct sockaddr *)&dest, sizeof dest);
if (result <= 0) { if (result <= 0) {
debug(LOG_ERR, "write on socket failed: %s\n", log_error("write on socket failed: %s",
strerror(errno)); strerror(errno));
} }
out_fd: out_fd:
close(fd); close(fd);

@@ -7,61 +7,40 @@
#include "log.h" #include "log.h"
static void set_cap(uid_t uid, gid_t gid, char *captxt) void set_cap(uid_t uid, gid_t gid, char *captxt)
{ {
cap_t caps; cap_t caps;
if (!captxt) { if (!captxt) {
log_line(LOG_ERR, "FATAL - set_cap: captxt == NULL\n"); log_error("FATAL - set_cap: captxt == NULL");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (prctl(PR_SET_KEEPCAPS, 1)) { if (prctl(PR_SET_KEEPCAPS, 1)) {
log_line(LOG_ERR, "FATAL - set_cap: prctl() failed\n"); log_error("FATAL - set_cap: prctl() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (setgroups(0, NULL) == -1) { if (setgroups(0, NULL) == -1) {
log_line(LOG_ERR, "FATAL - set_cap: setgroups() failed\n"); log_error("FATAL - set_cap: setgroups() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (setegid(gid) == -1 || seteuid(uid) == -1) { if (setegid(gid) == -1 || seteuid(uid) == -1) {
log_line(LOG_ERR, "FATAL - set_cap: seteuid() failed\n"); log_error("FATAL - set_cap: seteuid() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
caps = cap_from_text(captxt); caps = cap_from_text(captxt);
if (!caps) { if (!caps) {
log_line(LOG_ERR, "FATAL - set_cap: cap_from_text() failed\n"); log_error("FATAL - set_cap: cap_from_text() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (cap_set_proc(caps) == -1) { if (cap_set_proc(caps) == -1) {
log_line(LOG_ERR, "FATAL - set_cap: cap_set_proc() failed\n"); log_error("FATAL - set_cap: cap_set_proc() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
cap_free(caps); cap_free(caps);
} }
void drop_root(uid_t uid, gid_t gid, char *captxt)
{
if (!captxt) {
log_line(LOG_ERR, "FATAL - drop_root: captxt == NULL\n");
exit(EXIT_FAILURE);
}
if (uid == 0 || gid == 0) {
log_line(LOG_ERR, "FATAL - drop_root: attempt to drop root to root?\n");
exit(EXIT_FAILURE);
}
set_cap(uid, gid, captxt);
if (setregid(gid, gid) == -1 || setreuid(uid, uid) == -1) {
log_line(LOG_ERR, "FATAL - drop_root: failed to drop root!\n");
exit(EXIT_FAILURE);
}
}

@@ -1,2 +1,6 @@
void drop_root(uid_t uid, gid_t gid, char *captxt); #ifndef ROOTCAP_H_
#define ROOTCAP_H_
void set_cap(uid_t uid, gid_t gid, char *captxt);
#endif /* ROOTCAP_H_ */

@@ -123,7 +123,7 @@ static int open_ifch(void) {
ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
if (ret == -1) { if (ret == -1) {
log_line(LOG_ERR, "unable to connect to ifchd!\n"); log_error("unable to connect to ifchd!");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -139,14 +139,14 @@ sockwrite_again:
if (ret == -1) { if (ret == -1) {
if (errno == EAGAIN) if (errno == EAGAIN)
goto sockwrite_again; goto sockwrite_again;
log_line(LOG_ERR, "error while writing to unix socket!\n"); log_error("error while writing to unix socket!");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (ret < 0) ret = 0; if (ret < 0) ret = 0;
if ((unsigned int)ret < strlen(buf)) { if ((unsigned int)ret < strlen(buf)) {
log_line(LOG_ERR, "incomplete write!\n"); log_error("incomplete write!");
} }
debug(LOG_INFO, "writing: %s\n", (char *)buf); log_line("writing: %s", (char *)buf);
} }
static void deconfig_if(void) static void deconfig_if(void)
@@ -251,7 +251,7 @@ void run_script(struct dhcpMessage *packet, int mode)
default: default:
break; break;
} }
log_line(LOG_ERR, "invalid script mode: %d\n", mode); log_error("invalid script mode: %d", mode);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }

@@ -37,7 +37,7 @@
#include <netpacket/packet.h> #include <netpacket/packet.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include "log.h" #include "log.h"
#include "nstrl.h" #include "strl.h"
int read_interface(char *interface, int *ifindex, uint32_t *addr, int read_interface(char *interface, int *ifindex, uint32_t *addr,
unsigned char *arp) unsigned char *arp)
@@ -48,39 +48,39 @@ int read_interface(char *interface, int *ifindex, uint32_t *addr,
memset(&ifr, 0, sizeof(struct ifreq)); memset(&ifr, 0, sizeof(struct ifreq));
if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
log_line(LOG_ERR, "socket failed!: %s\n", strerror(errno)); log_error("socket failed!: %s", strerror(errno));
goto out; goto out;
} }
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;
strlcpy(ifr.ifr_name, interface, IFNAMSIZ); strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
if (addr) { if (addr) {
if (ioctl(fd, SIOCGIFADDR, &ifr)) { if (ioctl(fd, SIOCGIFADDR, &ifr)) {
log_line(LOG_ERR, "Couldn't get IP for %s.\n", strerror(errno)); log_error("Couldn't get IP for %s.", strerror(errno));
goto out_fd; goto out_fd;
} }
our_ip = (struct sockaddr_in *) &ifr.ifr_addr; our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
*addr = our_ip->sin_addr.s_addr; *addr = our_ip->sin_addr.s_addr;
debug(LOG_INFO, "%s (our ip) = %s\n", ifr.ifr_name, log_line("%s (our ip) = %s", ifr.ifr_name,
inet_ntoa(our_ip->sin_addr)); inet_ntoa(our_ip->sin_addr));
} }
if (ioctl(fd, SIOCGIFINDEX, &ifr)) { if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
log_line(LOG_ERR, "SIOCGIFINDEX failed!: %s\n", strerror(errno)); log_error("SIOCGIFINDEX failed!: %s", strerror(errno));
goto out_fd; goto out_fd;
} }
debug(LOG_INFO, "adapter index %d\n", ifr.ifr_ifindex); log_line("adapter index %d", ifr.ifr_ifindex);
*ifindex = ifr.ifr_ifindex; *ifindex = ifr.ifr_ifindex;
if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
log_line(LOG_ERR, "Couldn't get MAC for %s\n", strerror(errno)); log_error("Couldn't get MAC for %s", strerror(errno));
goto out_fd; goto out_fd;
} }
memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
debug(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x\n", log_line("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
ret = 0; ret = 0;
out_fd: out_fd:
@@ -96,9 +96,9 @@ int listen_socket(unsigned int ip, int port, char *inf)
struct sockaddr_in addr; struct sockaddr_in addr;
int n = 1; int n = 1;
debug(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf); log_line("Opening listen socket on 0x%08x:%d %s", ip, port, inf);
if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
debug(LOG_ERR, "socket call failed: %s\n", strerror(errno)); log_error("socket call failed: %s", strerror(errno));
goto out; goto out;
} }
@@ -132,9 +132,9 @@ int raw_socket(int ifindex)
int fd; int fd;
struct sockaddr_ll sock; struct sockaddr_ll sock;
debug(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex); log_line("Opening raw socket on ifindex %d", ifindex);
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
debug(LOG_ERR, "socket call failed: %s\n", strerror(errno)); log_error("socket call failed: %s", strerror(errno));
goto out; goto out;
} }
@@ -142,7 +142,7 @@ int raw_socket(int ifindex)
sock.sll_protocol = htons(ETH_P_IP); sock.sll_protocol = htons(ETH_P_IP);
sock.sll_ifindex = ifindex; sock.sll_ifindex = ifindex;
if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
debug(LOG_ERR, "bind call failed: %s\n", strerror(errno)); log_error("bind call failed: %s", strerror(errno));
goto out_fd; goto out_fd;
} }