Makefile | 14 +++--- Makefile.conf | 2 +- README | 16 ++++++ client/Makefile.dist | 2 +- client/dhclient.c | 33 +++++++++---- client/scripts/linux | 51 +++++++++++++------- common/Makefile.dist | 4 +- common/bpf.c | 2 +- common/comapi.c | 2 +- common/dns.c | 4 +- common/droproot.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ common/inet.c | 2 +- common/lpf.c | 1 + common/packet.c | 1 + common/parse.c | 31 ++++++++++-- common/print.c | 23 +++++---- common/tree.c | 18 ++++---- common/upf.c | 2 +- dhcpctl/dhcpctl.3 | 5 +- dhcpctl/omshell.c | 2 +- dst/Makefile.dist | 4 +- dst/dst_api.c | 10 ++++- dst/dst_support.c | 4 +- dst/hmac_link.c | 2 +- includes/cf/linux.h | 4 +- includes/dhcpd.h | 3 + minires/res_mkupdate.c | 8 ++-- minires/res_query.c | 2 +- omapip/errwarn.c | 82 ++++++++++++++++++++------------ omapip/iscprint.c | 18 ++++---- omapip/result.c | 2 +- relay/Makefile.dist | 2 +- relay/dhcrelay.8 | 22 ++++++++- relay/dhcrelay.c | 49 +++++++++++++------ server/Makefile.dist | 2 +- server/confpars.c | 7 ++- server/db.c | 4 +- server/ddns.c | 4 +- server/dhcp.c | 6 ++- server/dhcpd.8 | 19 ++++++++ server/dhcpd.c | 83 +++++++++++++++++++++----------- server/dhcpd.conf.5 | 21 ++++----- server/failover.c | 12 ++-- server/omapi.c | 2 +- 44 files changed, 506 insertions(+), 202 deletions(-) diff --git a/Makefile b/Makefile index 78867f8..3bbc8b8 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ all: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make all); \ + $(MAKE) -C work.$$sysname all; \ fi install: @@ -41,7 +41,7 @@ install: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make install); \ + $(MAKE) -C work.$$sysname install; \ fi depend: @@ -49,7 +49,7 @@ depend: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make depend); \ + $(MAKE) -C work.$$sysname depend; \ fi clean: @@ -57,7 +57,7 @@ clean: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make clean); \ + $(MAKE) -C work.$$sysname clean; \ fi realclean: @@ -65,7 +65,7 @@ realclean: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make realclean); \ + $(MAKE) -C work.$$sysname realclean; \ fi distclean: @@ -73,7 +73,7 @@ distclean: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make distclean); \ + $(MAKE) -C work.$$sysname distclean; \ fi links: @@ -81,6 +81,6 @@ links: if [ ! -d work.$$sysname ]; then \ echo No build directory for $$sysname - please run ./configure.; \ else \ - (cd work.$$sysname; make links); \ + $(MAKE) -C work.$$sysname links; \ fi diff --git a/Makefile.conf b/Makefile.conf index acdfb58..c6cb3ea 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -50,7 +50,7 @@ DEBUG = -g #WARNERR = -Werror RANLIB = ranlib MKDEP = mkdep -CLIENT_PATH = '"PATH=/usr/ucb:/usr/bin:/usr/sbin:/bin:/sbin"' +CLIENT_PATH = '"PATH=/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin"' BINDLIB = ../minires/libres.a BINDINC = diff --git a/README b/README index 2aa92bd..4747c9d 100644 --- a/README +++ b/README @@ -1,6 +1,7 @@ Internet Systems Consortium DHCP Distribution Version 3.1-ESV-R3 July 27, 2011 + (with modifications for ALT Linux) README FILE @@ -458,6 +459,21 @@ for AIX would be welcome. SUPPORT +Please note the following before requesting help: + +This software is a part of the Internet Software Consortium's DHCP suite +with modifications for ALT Linux. +The ISC folks quite reasonably require that you do not bother them with +questions on software that includes third-party modifications and might +not be based off their latest code. Hence, please direct any questions +to the community@ mailing list instead; the subscription instructions +are given at http://lists.altlinux.org/mailman/listinfo/community . + +The rest of this section describes the ISC's original guidelines on +requesting support and/or reporting bugs. These will only apply to +you if you reproduce your problem on the latest version of ISC's DHCP +suite as available from ftp://ftp.isc.org . + The Internet Systems Consortium DHCP server is developed and distributed by ISC in the public trust, thanks to the generous donations of its sponsors. ISC now also offers commercial quality support contracts for diff --git a/client/Makefile.dist b/client/Makefile.dist index c123963..5ee6e71 100644 --- a/client/Makefile.dist +++ b/client/Makefile.dist @@ -128,6 +128,6 @@ dhclient.leases.cat5: dhclient.leases.man5 dhclient: $(OBJS) $(DHCPLIB) - $(CC) $(LFLAGS) -o $(PROG) $(OBJS) $(DHCPLIB) $(LIBS) + $(CC) -pie $(LFLAGS) -o $(PROG) $(OBJS) $(DHCPLIB) $(LIBS) # Dependencies (semi-automatically-generated) diff --git a/client/dhclient.c b/client/dhclient.c index 921dade..79c52c9 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -262,9 +262,9 @@ int main (argc, argv, envp) if (!quiet) { log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info ("%s", copyright); + log_info ("%s", arr); + log_info ("%s", url); log_info ("%s", ""); } else log_perror = 0; @@ -470,9 +470,9 @@ int main (argc, argv, envp) static void usage () { log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info ("%s", copyright); + log_info ("%s", arr); + log_info ("%s", url); log_error ("Usage: dhclient [-1dqr] [-nw] [-p ] %s", "[-s server]"); @@ -1092,7 +1092,8 @@ void dhcpoffer (packet) return; } - sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr)); + snprintf (obuf, sizeof(obuf), + "%s from %s", name, piaddr (packet -> client_addr)); /* If this lease doesn't supply the minimum required parameters, @@ -2648,7 +2656,7 @@ void client_envadd (struct client_state *client, { char spbuf [1024]; char *s; - unsigned len, i; + int len; struct string_list *val; va_list list; @@ -2656,6 +2664,11 @@ void client_envadd (struct client_state *client, len = vsnprintf (spbuf, sizeof spbuf, fmt, list); va_end (list); +/* Handle truncation on glibc 2.0.x or possible unexpected errors on others; + * avoid integer overflow in the addition below. */ + if (len < 0 || len > 0x3fffffff) + return; + val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ + len + sizeof *val, MDL); if (!val) diff --git a/client/scripts/linux b/client/scripts/linux index 31ddd2f..26a2d2e 100755 --- a/client/scripts/linux +++ b/client/scripts/linux @@ -1,8 +1,6 @@ #!/bin/bash # dhclient-script for Linux. Dan Halbert, March, 1997. # Updated for Linux 2.[12] by Brian J. Murrell, January 1999. -# No guarantees about this. I'm a novice at the details of Linux -# networking. # Notes: @@ -19,26 +19,16 @@ # address if it is not supplied. This might be much more easily done # by the dhclient C code, and passed on. -# 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious -# of the $1 in its args. - make_resolv_conf() { - if [ x"$new_domain_name_servers" != x ]; then - cat /dev/null > /etc/resolv.conf.dhclient - chmod 644 /etc/resolv.conf.dhclient - if [ x"$new_domain_search" != x ]; then - echo search $new_domain_search >> /etc/resolv.conf.dhclient - elif [ x"$new_domain_name" != x ]; then - # Note that the DHCP 'Domain Name Option' is really just a domain - # name, and that this practice of using the domain name option as - # a search path is both nonstandard and deprecated. - echo search $new_domain_name >> /etc/resolv.conf.dhclient + if [ -n "$new_domain_name" ] || [ -n "$new_domain_name_servers" ]; then + echo '; generated by /sbin/dhclient-script' > /etc/resolv.conf + chmod 644 /etc/resolv.conf + if [ -n "$new_domain_name" ]; then + echo search $new_domain_name >> /etc/resolv.conf fi for nameserver in $new_domain_name_servers; do - echo nameserver $nameserver >>/etc/resolv.conf.dhclient + echo nameserver $nameserver >>/etc/resolv.conf done - - mv /etc/resolv.conf.dhclient /etc/resolv.conf fi } @@ -53,6 +51,22 @@ if [ -f /etc/dhclient-enter-hooks ]; then fi fi +cd /etc/sysconfig/network-scripts +. /etc/sysconfig/network-scripts/network-functions +. /etc/rc.d/init.d/functions + +[ -f ../network ] && . ../network +[ -f ../networking/network ] && . ../networking/network + +CONFIG="ifcfg-$interface" + +[ -f "${CONFIG}" ] || { + echo $"$0: configuration for $interface not found." >&2 + exit_with_hooks 1 +} + +source_config + release=`uname -r` release=`expr $release : '\(.*\)\..*'` relminor=`echo $release |sed -e 's/[0-9]*\.\([0-9][0-9]*\)\(\..*\)*$/\1/'` @@ -122,14 +122,10 @@ if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then - current_hostname=`hostname` - if [ x$current_hostname = x ] || \ - [ x$current_hostname = "x(none)" ] || \ - [ x$current_hostname = xlocalhost ] || \ - [ x$current_hostname = x$old_host_name ]; then - if [ x$new_host_name != x$old_host_name ]; then - hostname "$new_host_name" - fi + if [ -n "$new_host_name" ] && need_hostname; then + if need_hostname || [ "`hostname`" != "$new_host_name" ]; then + hostname $new_host_name + fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ @@ -146,7 +157,10 @@ if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address $interface:0 fi - make_resolv_conf + if [ "${PEERDNS}" != "no" ]; then + make_resolv_conf + fi + exit_with_hooks 0 fi @@ -174,7 +188,7 @@ if [ x$reason = xTIMEOUT ]; then ifconfig $interface inet $new_ip_address $new_subnet_arg \ $new_broadcast_arg $mtu_arg set $new_routers - if ping -q -c 1 $1; then + if ping -q -c 1 -w 10 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg @@ -188,7 +201,9 @@ if [ x$reason = xTIMEOUT ]; then for router in $new_routers; do route add default gw $router done - make_resolv_conf + if [ "${PEERDNS}" != "no" ]; then + make_resolv_conf + fi exit_with_hooks 0 fi ifconfig $interface inet 0 down diff --git a/common/Makefile.dist b/common/Makefile.dist index 5e40a0f..cd2defe 100644 --- a/common/Makefile.dist +++ b/common/Makefile.dist @@ -25,11 +25,11 @@ SEDMANPAGES = dhcp-options.man5 dhcp-eval.man5 SRC = raw.c parse.c nit.c icmp.c dispatch.c conflex.c upf.c bpf.c socket.c \ lpf.c dlpi.c packet.c tr.c ethernet.c memory.c print.c options.c \ inet.c tree.c tables.c alloc.c fddi.c ctrace.c dns.c resolv.c \ - execute.c discover.c comapi.c + execute.c discover.c comapi.c droproot.c OBJ = raw.o parse.o nit.o icmp.o dispatch.o conflex.o upf.o bpf.o socket.o \ lpf.o dlpi.o packet.o tr.o ethernet.o memory.o print.o options.o \ inet.o tree.o tables.o alloc.o fddi.o ctrace.o dns.o resolv.o \ - execute.o discover.o comapi.o + execute.o discover.o comapi.o droproot.o MAN = dhcp-options.5 dhcp-eval.5 INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes diff --git a/common/bpf.c b/common/bpf.c index 6a387d9..6f50f11 100644 --- a/common/bpf.c +++ b/common/bpf.c @@ -91,7 +91,7 @@ int if_register_bpf (info) /* Open a BPF device */ for (b = 0; 1; b++) { /* %Audit% 31 bytes max. %2004.06.17,Safe% */ - sprintf(filename, BPF_FORMAT, b); + snprintf(filename, sizeof(filename), BPF_FORMAT, b); sock = open (filename, O_RDWR, 0); if (sock < 0) { if (errno == EBUSY) { diff --git a/common/comapi.c b/common/comapi.c index 1307968..c58ffde 100644 --- a/common/comapi.c +++ b/common/comapi.c @@ -288,7 +288,7 @@ isc_result_t dhcp_group_signal_handler (omapi_object_t *h, /* Group objects always have to have names. */ if (!group -> name) { char hnbuf [64]; - sprintf (hnbuf, "ng%08lx%08lx", + snprintf (hnbuf, sizeof(hnbuf), "ng%08lx%08lx", (unsigned long)cur_time, (unsigned long)group); group -> name = dmalloc (strlen (hnbuf) + 1, MDL); diff --git a/common/dns.c b/common/dns.c index 03a76a8..c489201 100644 --- a/common/dns.c +++ b/common/dns.c @@ -533,7 +533,7 @@ isc_result_t ddns_update_a (struct data_string *ddns_fwd_name, return ISC_R_INVALIDARG; /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe% */ - sprintf (ddns_address, "%u.%u.%u.%u", + snprintf (ddns_address, sizeof(ddns_address), "%u.%u.%u.%u", ddns_addr.iabuf[0], ddns_addr.iabuf[1], ddns_addr.iabuf[2], ddns_addr.iabuf[3]); @@ -794,7 +794,7 @@ isc_result_t ddns_remove_a (struct data_string *ddns_fwd_name, return ISC_R_INVALIDARG; /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe% */ - sprintf (ddns_address, "%u.%u.%u.%u", + snprintf (ddns_address, sizeof(ddns_address), "%u.%u.%u.%u", ddns_addr.iabuf[0], ddns_addr.iabuf[1], ddns_addr.iabuf[2], ddns_addr.iabuf[3]); diff --git a/common/droproot.c b/common/droproot.c new file mode 100644 index 0000000..36c42dd --- /dev/null +++ b/common/droproot.c @@ -0,0 +1,121 @@ +#include "dhcpd.h" +#include +#include +#include +#define group real_group +#include +#undef group + +#include +#include + +static int minimized = 0; + +void +dhcpd_priv_minimize(const char *user, const char *dir) +{ + struct passwd *pw; + uid_t uid; + gid_t gid; + + if (!*user) + return; + + if (!(pw = getpwnam(user))) + log_fatal("Failed to lower privileges: getpwnam: %s", user); + + uid = pw->pw_uid; + gid = pw->pw_gid; + + tzset(); + + if (initgroups(user, gid)) + log_fatal("Failed to lower privileges: initgroups: %s/%u: %m", + user, (unsigned) gid); + + endpwent(); + + if (*dir && (chdir(dir) || chroot("."))) + log_fatal("Failed to lower privileges: chroot: %s: %m", dir); + + if (setgid(gid)) + log_fatal("Failed to lower privileges: setgid: %s/%u: %m", + user, (unsigned) gid); + + if (prctl(PR_SET_KEEPCAPS, 1)) + log_fatal("Failed to lower privileges: prctl: %m"); + + if (setreuid(uid, uid)) + log_fatal("Failed to lower privileges: setreuid: %s/%u: %m", + user, (unsigned) uid); + + cap_t caps = cap_from_text("cap_net_bind_service=ep"); + + if (!caps) + log_fatal("Failed to lower privileges: cap_from_text: %m"); + + if (cap_set_proc(caps) < 0) + log_fatal("Failed to lower privileges: cap_set_proc: %m"); + + cap_free(caps); + minimized = 1; +} + +static void +drop_minimized(void) +{ + cap_t caps = cap_from_text("all-ep"); + if (!caps) + log_fatal("Failed to lower privileges: cap_from_text: %m"); + + if (cap_set_proc(caps) < 0) + log_fatal("Failed to lower privileges: cap_set_proc: %m"); + + cap_free(caps); +} + +static void +drop_all(const char *user, const char *dir) +{ + struct passwd *pw; + uid_t uid; + gid_t gid; + + if (!(pw = getpwnam(user))) + log_fatal("Failed to lower privileges: getpwnam: %s", user); + + uid = pw->pw_uid; + gid = pw->pw_gid; + + tzset(); + + if (initgroups(user, gid)) + log_fatal("Failed to lower privileges: initgroups: %s/%u: %m", + user, (unsigned) gid); + + endpwent(); + + if (*dir && (chdir(dir) || chroot("."))) + log_fatal("Failed to lower privileges: chroot: %s: %m", dir); + + if (setgid(gid)) + log_fatal("Failed to lower privileges: setgid: %s/%u: %m", + user, (unsigned) gid); + + if (setuid(uid)) + log_fatal("Failed to lower privileges: setuid: %s/%u: %m", + user, (unsigned) uid); +} + + +void +dhcpd_priv_drop(const char *user, const char *dir) +{ + if (!*user) + return; + + if (minimized) + drop_minimized(); + else + drop_all(user, dir); +} diff --git a/common/inet.c b/common/inet.c index 3c86e5a..488b15a 100644 --- a/common/inet.c +++ b/common/inet.c @@ -188,7 +188,7 @@ int addr_eq (addr1, addr2) char *piaddr (addr) struct iaddr addr; { - static char pbuf [4 * 16]; + static char pbuf [4 * sizeof(addr.iabuf)]; char *s = pbuf; int i; diff --git a/common/lpf.c b/common/lpf.c index dc7f3f2..3f19b43 100644 --- a/common/lpf.c +++ b/common/lpf.c @@ -253,6 +253,7 @@ static void lpf_tr_filter_setup (info) /* Set up the bpf filter program structure. This is defined in bpf.c */ + memset(&p, '\0', sizeof p); p.len = dhcp_bpf_tr_filter_len; p.filter = dhcp_bpf_tr_filter; diff --git a/common/packet.c b/common/packet.c index 668106c..fdd569f 100644 --- a/common/packet.c +++ b/common/packet.c @@ -141,6 +141,7 @@ void assemble_udp_ip_header (interface, buf, bufix, struct udphdr udp; /* Fill out the IP header */ + memset( &ip, '\0', sizeof ip); IP_V_SET (&ip, 4); IP_HL_SET (&ip, 20); ip.ip_tos = IPTOS_LOWDELAY; diff --git a/common/parse.c b/common/parse.c index 9efd146..f4d6c46 100644 --- a/common/parse.c +++ b/common/parse.c @@ -4798,6 +4798,25 @@ int parse_X (cfile, buf, max) return len; } +static ssize_t +write_loop (int fd, const char *buffer, size_t count) +{ + ssize_t offset = 0; + + while (count > 0) + { + ssize_t block = write (fd, &buffer[offset], count); + + if (block < 0 && errno == EINTR) + continue; + if (block <= 0) + return offset ? : block; + offset += block; + count -= block; + } + return offset; +} + int parse_warn (struct parse *cfile, const char *fmt, ...) { va_list list; @@ -4838,14 +4857,14 @@ int parse_warn (struct parse *cfile, const char *fmt, ...) #endif if (log_perror) { - IGNORE_RET(write(STDERR_FILENO, mbuf, strlen (mbuf))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); - IGNORE_RET(write(STDERR_FILENO, cfile -> token_line, + IGNORE_RET(write_loop (STDERR_FILENO, mbuf, strlen (mbuf))); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); + IGNORE_RET(write_loop (STDERR_FILENO, cfile -> token_line, strlen (cfile -> token_line))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); if (cfile -> lexchar < 81) - IGNORE_RET(write(STDERR_FILENO, lexbuf, lix)); - IGNORE_RET(write(STDERR_FILENO, "^\n", 2)); + IGNORE_RET(write_loop (STDERR_FILENO, lexbuf, lix)); + IGNORE_RET(write_loop (STDERR_FILENO, "^\n", 2)); } cfile -> warnings_occurred = 1; diff --git a/common/print.c b/common/print.c index 446de78..969f8ab 100644 --- a/common/print.c +++ b/common/print.c @@ -437,7 +437,7 @@ char *print_dec_1 (val) unsigned long val; { static char vbuf [32]; - sprintf (vbuf, "%lu", val); + snprintf (vbuf, sizeof(vbuf), "%lu", val); return vbuf; } @@ -445,7 +445,7 @@ char *print_dec_2 (val) unsigned long val; { static char vbuf [32]; - sprintf (vbuf, "%lu", val); + snprintf (vbuf, sizeof(vbuf), "%lu", val); return vbuf; } @@ -478,7 +478,7 @@ static unsigned print_subexpression (expr, buf, len) case expr_check: rv = 10 + strlen (expr -> data.check -> name); if (len > rv) { - sprintf (buf, "(check %s)", + snprintf (buf, len, "(check %s)", expr -> data.check -> name); return rv; } @@ -585,7 +585,7 @@ static unsigned print_subexpression (expr, buf, len) case expr_host_lookup: rv = 15 + strlen (expr -> data.host_lookup -> hostname); if (len > rv) { - sprintf (buf, "(dns-lookup %s)", + snprintf (buf, len, "(dns-lookup %s)", expr -> data.host_lookup -> hostname); return rv; } @@ -669,7 +669,7 @@ static unsigned print_subexpression (expr, buf, len) rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) + strlen (expr -> data.option -> universe -> name)); if (len > rv) { - sprintf (buf, "(option %s.%s)", + snprintf (buf, len, "(option %s.%s)", expr -> data.option -> universe -> name, expr -> data.option -> name); return rv; @@ -805,7 +805,7 @@ static unsigned print_subexpression (expr, buf, len) rv = 10 + (strlen (expr -> data.option -> name) + strlen (expr -> data.option -> universe -> name)); if (len > rv) { - sprintf (buf, "(exists %s.%s)", + snprintf (buf, len, "(exists %s.%s)", expr -> data.option -> universe -> name, expr -> data.option -> name); return rv; @@ -815,7 +815,8 @@ static unsigned print_subexpression (expr, buf, len) case expr_variable_exists: rv = 10 + strlen (expr -> data.variable); if (len > rv) { - sprintf (buf, "(defined %s)", expr -> data.variable); + snprintf (buf, len, + "(defined %s)", expr -> data.variable); return rv; } break; @@ -823,7 +824,7 @@ static unsigned print_subexpression (expr, buf, len) case expr_variable_reference: rv = strlen (expr -> data.variable); if (len > rv) { - sprintf (buf, "%s", expr -> data.variable); + snprintf (buf, len, "%s", expr -> data.variable); return rv; } break; @@ -1106,7 +1107,7 @@ int token_indent_data_string (FILE *file, int col, int indent, } for (i = 0; i < data -> len; i++) { - sprintf (obuf, "%2.2x", data -> data [i]); + snprintf (obuf, sizeof(obuf), "%2.2x", data -> data [i]); col = token_print_indent (file, col, indent, i == 0 ? prefix : "", (i + 1 == data -> len diff --git a/common/tree.c b/common/tree.c index 56d262f..7130839 100644 --- a/common/tree.c +++ b/common/tree.c @@ -738,8 +738,8 @@ int evaluate_dns_expression (result, packet, lease, client_state, in_options, (*result) -> r_data = (*result) -> r_data_ephem; /*%Audit% 16 bytes max. %2004.06.17,Safe%*/ - sprintf ((char *)(*result) -> r_data_ephem, - "%u.%u.%u.%u", + snprintf ((char *)(*result) -> r_data_ephem, + 16, "%u.%u.%u.%u", data.data [0] & 0xff, data.data [1] & 0xff, data.data [2] & 0xff, @@ -3428,7 +3428,7 @@ int write_expression (file, expr, col, indent, firstp) col = write_expression (file, expr -> data.extract_int, col, indent, 1); col = token_print_indent (file, col, scol, "", " ", ","); - sprintf (obuf, "%d", width); + snprintf (obuf, sizeof(obuf), "%d", width); col = token_print_indent (file, col, scol, " ", "", obuf); col = token_print_indent (file, col, indent, "", "", ")"); break; @@ -3451,7 +3451,7 @@ int write_expression (file, expr, col, indent, firstp) col = write_expression (file, expr -> data.extract_int, col, indent, 1); col = token_print_indent (file, col, scol, "", " ", ","); - sprintf (obuf, "%d", width); + snprintf (obuf, sizeof(obuf), "%d", width); col = token_print_indent (file, col, scol, " ", "", obuf); col = token_print_indent (file, col, indent, "", "", ")"); @@ -3466,7 +3466,7 @@ int write_expression (file, expr, col, indent, firstp) goto encode_int; case expr_const_int: - sprintf (obuf, "%lu", expr -> data.const_int); + snprintf (obuf, sizeof(obuf), "%lu", expr -> data.const_int); col = token_print_indent (file, col, indent, "", "", obuf); break; @@ -3615,11 +3615,11 @@ int write_expression (file, expr, col, indent, firstp) col = token_print_indent (file, col, indent, " ", "", "("); scol = col; - sprintf (obuf, "%d", expr -> data.ns_add.rrclass); + snprintf (obuf, sizeof(obuf), "%d", expr -> data.ns_add.rrclass); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); - sprintf (obuf, "%d", expr -> data.ns_add.rrtype); + snprintf (obuf, sizeof(obuf), "%d", expr -> data.ns_add.rrtype); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); @@ -3644,11 +3644,11 @@ int write_expression (file, expr, col, indent, firstp) "("); finish_ns_small: scol = col; - sprintf (obuf, "%d", expr -> data.ns_add.rrclass); + snprintf (obuf, sizeof(obuf), "%d", expr -> data.ns_add.rrclass); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); - sprintf (obuf, "%d", expr -> data.ns_add.rrtype); + snprintf (obuf, sizeof(obuf), "%d", expr -> data.ns_add.rrtype); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); diff --git a/common/upf.c b/common/upf.c index 89c217a..116449b 100644 --- a/common/upf.c +++ b/common/upf.c @@ -80,7 +80,7 @@ int if_register_upf (info) /* Open a UPF device */ for (b = 0; 1; b++) { /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */ - sprintf(filename, "/dev/pf/pfilt%d", b); + snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b); sock = open (filename, O_RDWR, 0); if (sock < 0) { diff --git a/dhcpctl/dhcpctl.3 b/dhcpctl/dhcpctl.3 index 352bf3b..880285d 100644 --- a/dhcpctl/dhcpctl.3 +++ b/dhcpctl/dhcpctl.3 @@ -43,7 +43,8 @@ .\" .\" .Sh SYNOPSIS -.Fd #include +.Fd #include +.sp .Ft dhcpctl_status .Fo dhcpctl_initialize .Fa void @@ -426,7 +427,7 @@ that most error checking has been ommitted for brevity. #include #include -#include +#include int main (int argc, char **argv) { dhcpctl_data_string ipaddrstring = NULL; diff --git a/dhcpctl/omshell.c b/dhcpctl/omshell.c index 4de6119..9fe0d6b 100644 --- a/dhcpctl/omshell.c +++ b/dhcpctl/omshell.c @@ -184,7 +184,7 @@ int main (int argc, char **argv, char **envp) check(status, "new_parse()"); token = next_token (&val, (unsigned *)0, cfile); - switch (token) { + switch ((int) token) { default: parse_warn (cfile, "unknown token: %s", val); skip_to_semi (cfile); diff --git a/dst/Makefile.dist b/dst/Makefile.dist index ffe7e4e..9282e59 100644 --- a/dst/Makefile.dist +++ b/dst/Makefile.dist @@ -30,7 +30,9 @@ CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) -DHMAC_MD5 -DMINIRES_LIB all: libdst.a -install: +install: all + mkdir -p $(DESTDIR)$(LIBDIR) + $(INSTALL) libdst.a $(DESTDIR)$(LIBDIR)/ libdst.a: $(OBJ) rm -f dst.a diff --git a/dst/dst_api.c b/dst/dst_api.c index 64114cb..ff396f2 100644 --- a/dst/dst_api.c +++ b/dst/dst_api.c @@ -440,6 +440,7 @@ dst_s_write_private_key(const DST_KEY *key) if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", file, out_len, nn, errno)); + fclose(fp); return (-5); } fclose(fp); @@ -526,6 +527,7 @@ dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg) /* Locate and skip "KEY" */ if (c != 'K' && c != 'k') { EREPORT(("\"KEY\" doesn't appear in file: %s", name)); + fclose(fp); return NULL; } while ((c = getc(fp)) != EOF) @@ -542,12 +542,14 @@ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" ,name)); + fclose(fp); return (NULL); } /* read in the key string */ if ((fgets(enckey, sizeof(enckey), fp) == NULL) && (ferror(fp) != 0)) { EREPORT(("dst_read_public_kety(): Error reading key\n")); + fclose(fp); return (NULL); } @@ -551,6 +558,7 @@ dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg) break; if (!feof(fp)) { EREPORT(("Key too long in file: %s", name)); + fclose(fp); return NULL; } fclose(fp); diff --git a/dst/dst_support.c b/dst/dst_support.c index 581445b..a8c1ba8 100644 --- a/dst/dst_support.c +++ b/dst/dst_support.c @@ -418,8 +418,8 @@ dst_s_build_filename(char *filename, const char *name, unsigned id, if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix)) return (-1); my_id = id; - sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id, - (const char *) suffix); + snprintf(filename, filename_length, "K%s+%03d+%05d.%s", + name, alg, my_id, (const char *) suffix); if (strrchr(filename, '/')) return (-1); if (strrchr(filename, '\\')) diff --git a/dst/hmac_link.c b/dst/hmac_link.c index 90b92e2..ad95c7a 100644 --- a/dst/hmac_link.c +++ b/dst/hmac_link.c @@ -280,7 +280,7 @@ dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff, hkey = (HMAC_Key *) dkey->dk_KEY_struct; memset(buff, 0, buff_len); /* just in case */ /* write file header */ - sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC"); + snprintf(buff, buff_len, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC"); bp = (char *) strchr(buff, '\0'); b_len = buff_len - (bp - buff); diff --git a/includes/cf/linux.h b/includes/cf/linux.h index a286084..d37e335 100644 --- a/includes/cf/linux.h +++ b/includes/cf/linux.h @@ -83,11 +83,11 @@ extern int h_errno; directory. */ #ifndef _PATH_DHCPD_DB -#define _PATH_DHCPD_DB "/var/state/dhcp/dhcpd.leases" +#define _PATH_DHCPD_DB "/state/dhcpd.leases" #endif #ifndef _PATH_DHCLIENT_DB -#define _PATH_DHCLIENT_DB "/var/state/dhcp/dhclient.leases" +#define _PATH_DHCLIENT_DB "/var/lib/dhcp/dhclient/state/dhclient.leases" #endif /* Varargs stuff... */ diff --git a/includes/dhcpd.h b/includes/dhcpd.h index ba2911b..d6acec1 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -2643,3 +2643,6 @@ OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_link, dhcp_failover_link_t, #endif /* FAILOVER_PROTOCOL */ const char *binding_state_print (enum failover_state); + +extern void dhcpd_priv_minimize(const char *server_user, const char *server_jail); +extern void dhcpd_priv_drop(const char *server_user, const char *server_jail); diff --git a/minires/res_mkupdate.c b/minires/res_mkupdate.c index 19f2d50..537f636 100644 --- a/minires/res_mkupdate.c +++ b/minires/res_mkupdate.c @@ -1113,14 +1113,14 @@ cgetprotobynumber(int proto) { /* Host byte order. */ const char * res_protocolname(int num) { - static char number[8]; + static char number[2 + sizeof(num) * 3]; struct protoent *pp; if (protolist == (struct valuelist *)0) res_buildprotolist(); pp = cgetprotobynumber(num); if (pp == 0) { - (void) sprintf(number, "%d", num); + (void) snprintf(number, sizeof(number), "%d", num); return (number); } return (pp->p_name); @@ -1128,14 +1128,14 @@ res_protocolname(int num) { const char * res_servicename(u_int16_t port, const char *proto) { /* Host byte order. */ - static char number[8]; + static char number[2 + sizeof(port) * 3]; struct servent *ss; if (servicelist == (struct valuelist *)0) res_buildservicelist(); ss = cgetservbyport(htons(port), proto); if (ss == 0) { - (void) sprintf(number, "%d", port); + (void) snprintf(number, sizeof(number), "%d", port); return (number); } return (ss->s_name); diff --git a/minires/res_query.c b/minires/res_query.c index 7c3912f..170d999 100644 --- a/minires/res_query.c +++ b/minires/res_query.c @@ -375,7 +375,7 @@ res_nquerydomain(res_state statp, RES_SET_H_ERRNO(statp, NO_RECOVERY); return ISC_R_NOSPACE; } - sprintf(nbuf, "%s.%s", name, domain); + snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); } return res_nquery(statp, longname, class, type, answer, anslen, ansret); diff --git a/omapip/errwarn.c b/omapip/errwarn.c index be0e6d8..f1d7343 100644 --- a/omapip/errwarn.c +++ b/omapip/errwarn.c @@ -51,6 +51,25 @@ void (*log_cleanup) (void); static char mbuf [CVT_BUF_MAX + 1]; static char fbuf [CVT_BUF_MAX + 1]; +static ssize_t +write_loop (int fd, const char *buffer, size_t count) +{ + ssize_t offset = 0; + + while (count > 0) + { + ssize_t block = write (fd, &buffer[offset], count); + + if (block < 0 && errno == EINTR) + continue; + if (block <= 0) + return offset ? : block; + offset += block; + count -= block; + } + return offset; +} + /* Log an error message, then exit... */ void log_fatal (const char * fmt, ... ) @@ -67,33 +86,31 @@ void log_fatal (const char * fmt, ... ) va_end (list); #ifndef DEBUG - syslog (log_priority | LOG_ERR, "%s", mbuf); + if (*mbuf) + syslog (log_priority | LOG_ERR, "%s", mbuf); #endif /* Also log it to stderr? */ - if (log_perror) { - IGNORE_RET(write(STDERR_FILENO, mbuf, strlen (mbuf))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); + if (log_perror && *mbuf) { + IGNORE_RET(write_loop (STDERR_FILENO, mbuf, strlen (mbuf))); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); } #if !defined (NOMINUM) + log_error ("%s", "Please note the following before requesting help:"); log_error ("%s", ""); - log_error ("If you did not get this software from ftp.isc.org, please"); - log_error ("get the latest from ftp.isc.org and install that before"); - log_error ("requesting help."); - log_error ("%s", ""); - log_error ("If you did get this software from ftp.isc.org and have not"); - log_error ("yet read the README, please read it before requesting help."); - log_error ("If you intend to request help from the dhcp-server@isc.org"); - log_error ("mailing list, please read the section on the README about"); - log_error ("submitting bug reports and requests for help."); + log_error ("%s", "This software is a part of the Internet Software Consortium's DHCP suite"); + log_error ("%s", "with modifications for ALT Linux."); + log_error ("%s", "The ISC folks quite reasonably require that you do not bother them with"); + log_error ("%s", "questions on software that includes third-party modifications and might"); + log_error ("%s", "not be based off their latest code. Hence, please direct any questions"); + log_error ("%s", "to the community@ mailing list instead; the subscription instructions"); + log_error ("%s", "are given at http://lists.altlinux.org/mailman/listinfo/community ."); log_error ("%s", ""); - log_error ("Please do not under any circumstances send requests for"); - log_error ("help directly to the authors of this software - please"); - log_error ("send them to the appropriate mailing list as described in"); - log_error ("the README file."); + log_error ("%s", "Please also read the SUPPORT section on the README about"); + log_error ("%s", "submitting bug reports and requests for help."); log_error ("%s", ""); - log_error ("exiting."); + log_error ("%s", "exiting."); #endif if (log_cleanup) (*log_cleanup) (); @@ -116,12 +133,13 @@ int log_error (const char * fmt, ...) va_end (list); #ifndef DEBUG - syslog (log_priority | LOG_ERR, "%s", mbuf); + if (*mbuf) + syslog (log_priority | LOG_ERR, "%s", mbuf); #endif - if (log_perror) { - IGNORE_RET(write(STDERR_FILENO, mbuf, strlen (mbuf))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); + if (log_perror && *mbuf) { + IGNORE_RET(write_loop (STDERR_FILENO, mbuf, strlen (mbuf))); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); } return 0; @@ -143,12 +161,13 @@ int log_info (const char *fmt, ...) va_end (list); #ifndef DEBUG - syslog (log_priority | LOG_INFO, "%s", mbuf); + if (*mbuf) + syslog (log_priority | LOG_INFO, "%s", mbuf); #endif - if (log_perror) { - IGNORE_RET(write(STDERR_FILENO, mbuf, strlen (mbuf))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); + if (log_perror && *mbuf) { + IGNORE_RET(write_loop (STDERR_FILENO, mbuf, strlen (mbuf))); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); } return 0; @@ -170,12 +189,13 @@ int log_debug (const char *fmt, ...) va_end (list); #ifndef DEBUG - syslog (log_priority | LOG_DEBUG, "%s", mbuf); + if (*mbuf) + syslog (log_priority | LOG_DEBUG, "%s", mbuf); #endif - if (log_perror) { - IGNORE_RET(write(STDERR_FILENO, mbuf, strlen (mbuf))); - IGNORE_RET(write(STDERR_FILENO, "\n", 1)); + if (log_perror && *mbuf) { + IGNORE_RET(write_loop (STDERR_FILENO, mbuf, strlen (mbuf))); + IGNORE_RET(write_loop (STDERR_FILENO, "\n", 1)); } return 0; @@ -236,7 +256,7 @@ char *strerror (err) static char errbuf [128]; if (err < 0 || err >= sys_nerr) { - sprintf (errbuf, "Error %d", err); + snprintf (errbuf, sizeof(errbuf), "Error %d", err); return errbuf; } return sys_errlist [err]; diff --git a/omapip/iscprint.c b/omapip/iscprint.c index de331a1..e3e5e80 100644 --- a/omapip/iscprint.c +++ b/omapip/iscprint.c @@ -230,7 +230,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { head = ""; tmpui = tmpi; } - sprintf(buf, "%u", tmpui); + snprintf(buf, sizeof(buf), "%u", tmpui); goto printint; case 'o': if (q) @@ -239,7 +239,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { tmpui = va_arg(ap, long int); else tmpui = va_arg(ap, int); - sprintf(buf, alt ? "%#o" + snprintf(buf, sizeof(buf), alt ? "%#o" : "%o", tmpui); goto printint; case 'u': @@ -249,7 +249,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { tmpui = va_arg(ap, unsigned long int); else tmpui = va_arg(ap, unsigned int); - sprintf(buf, "%u", tmpui); + snprintf(buf, sizeof(buf), "%u", tmpui); goto printint; case 'x': if (q) @@ -263,7 +263,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (precision > 2) precision -= 2; } - sprintf(buf, "%x", tmpui); + snprintf(buf, sizeof(buf), "%x", tmpui); goto printint; case 'X': if (q) @@ -277,7 +277,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (precision > 2) precision -= 2; } - sprintf(buf, "%X", tmpui); + snprintf(buf, sizeof(buf), "%X", tmpui); goto printint; printint: if (precision != 0 || width != 0) { @@ -403,7 +403,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { break; case 'p': v = va_arg(ap, void *); - sprintf(buf, "%p", v); + snprintf(buf, sizeof(buf), "%p", v); length = strlen(buf); if (precision > length) zeropad = precision - length; @@ -479,7 +479,7 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { */ if (precision > 512) precision = 512; - sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "", + snprintf(fmt, sizeof(fmt), "%%%s%s.%lu%s%c", alt ? "#" : "", plus ? "+" : space ? " " : "", precision, l ? "L" : "", *format); switch (*format) { @@ -491,12 +491,12 @@ isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { #ifdef HAVE_LONG_DOUBLE if (l) { ldbl = va_arg(ap, long double); - sprintf(buf, fmt, ldbl); + snprintf(buf, sizeof(buf), fmt, ldbl); } else #endif { dbl = va_arg(ap, double); - sprintf(buf, fmt, dbl); + snprintf(buf, sizeof(buf), fmt, dbl); } length = strlen(buf); if (width > 0) { diff --git a/omapip/result.c b/omapip/result.c index 2274689..e598e26 100644 --- a/omapip/result.c +++ b/omapip/result.c @@ -114,6 +114,6 @@ const char *isc_result_totext (isc_result_t result) if (result >= ISC_R_SUCCESS && result < ISC_R_NRESULTS) return text [result]; - sprintf(ebuf, "unknown error: %d", result); + snprintf(ebuf, sizeof(ebuf), "unknown error: %d", result); return ebuf; } diff --git a/relay/Makefile.dist b/relay/Makefile.dist index 8f1da98..b5fc8c4 100644 --- a/relay/Makefile.dist +++ b/relay/Makefile.dist @@ -83,6 +83,6 @@ dhcrelay.man8: dhcrelay.8 -e "s#RUNDIR#$(VARRUN)#" < dhcrelay.8 >dhcrelay.man8 dhcrelay: dhcrelay.o $(DHCPLIB) - $(CC) $(LFLAGS) -o $(PROG) dhcrelay.o $(DHCPLIB) $(LIBS) + $(CC) -pie $(LFLAGS) -o $(PROG) dhcrelay.o $(DHCPLIB) $(LIBS) -lcap # Dependencies (semi-automatically-generated) diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8 index 115d8a3..82aff34 100644 --- a/relay/dhcrelay.8 +++ b/relay/dhcrelay.8 @@ -77,6 +77,14 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent | .I discard ] +[ +.B -u +.I user +] +[ +.B -j +.I chroot-dir +] .I server0 [ .I ...serverN @@ -139,6 +147,11 @@ This can be unhelpful in a system startup script - to disable this behaviour, specify the .B -q flag. +.PP +Upon startup, this version of dhcrelay will switch to a non-root +pseudo-user and enter a chroot jail. The default username (\fIdhcrelay\fR) +and the default chroot jail directory path (\fI/var/empty\fR) +may be overridden with the \fB-u\fR and \fB-j\fR options, respectively. .SH RELAY AGENT INFORMATION OPTIONS If the .B -a @@ -239,7 +252,12 @@ has been written for Internet Systems Consortium by Ted Lemon in cooperation with Vixie Enterprises. To learn more about Internet Systems Consortium, see -.B https://www.isc.org/isc. +.BR https://www.isc.org/isc . To learn more about Vixie Enterprises, see -.B http://www.vix.com. +.BR http://www.vix.com . +.PP +This version of dhcrelay has been modified for ALT Linux +.RB ( http://www.altlinux.com/ ). +In particular, the privilege reduction functionality and the \fB-u\fR +and \fB-j\fR options are Openwall/ALT Linux extensions. diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c index 5d19ec2..3eb629d 100644 --- a/relay/dhcrelay.c +++ b/relay/dhcrelay.c @@ -120,6 +120,8 @@ int quiet = 0; isc_result_t status; char *s; + char *server_user = "dhcrelay"; + char *server_jail = "/var/empty"; /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 2 (stderr) are open. To do this, we assume that when we @@ -129,10 +131,12 @@ fd = open("/dev/null", O_RDWR); if (fd == 1) fd = open("/dev/null", O_RDWR); - if (fd == 2) + if (fd == 2) { + fd = open("/dev/null", O_RDWR); log_perror = 0; /* No sense logging to /dev/null. */ - else if (fd != -1) - close(fd); + } + if (fd < 0) + log_fatal ("Can't open %s: %m", "/dev/null"); #ifdef SYSLOG_4_2 openlog ("dhcrelay", LOG_NDELAY); @@ -185,6 +190,14 @@ int main (argc, argv, envp) log_fatal("%s: packet length exceeds " "longest possible MTU\n", argv[i]); + } else if (!strcmp (argv [i], "-u")) { + if (++i == argc) + usage (); + server_user = argv[i]; + } else if (!strcmp (argv [i], "-j")) { + if (++i == argc) + usage (); + server_jail = argv[i]; } else if (!strcmp (argv [i], "-m")) { if (++i == argc) usage (); @@ -239,9 +252,9 @@ int main (argc, argv, envp) if (!quiet) { log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info ("%s", copyright); + log_info ("%s", arr); + log_info ("%s", url); } else { quiet = 0; log_perror = 0; @@ -310,12 +323,17 @@ int main (argc, argv, envp) } } - close (0); - close (1); - close (2); + if (dup2 (fd, 0) != 0 || + dup2 (fd, 1) != 1 || + dup2 (fd, 2) != 2) + log_fatal("Can't daemonize: %m"); + close (fd); + fd = -1; pid = setsid (); } + dhcpd_priv_drop(server_user, server_jail); + /* Start dispatching packets and timeouts... */ dispatch (); @@ -455,10 +473,11 @@ void relay (ip, packet, length, from_port, from, hfrom) static void usage () { - log_fatal ("Usage: dhcrelay [-p ] [-d] [-D] [-i %s%s%s%s", + log_fatal ("Usage: dhcrelay [-p ] [-d] [-D] [-i %s%s%s%s%s", "interface] [-q] [-a]\n ", "[-c count] [-A length] ", "[-m append|replace|forward|discard]\n", + "[-u user] [-j chroot-dir]\n", " [server1 [... serverN]]"); } diff --git a/server/Makefile.dist b/server/Makefile.dist index b7d1216..9202441 100644 --- a/server/Makefile.dist +++ b/server/Makefile.dist @@ -103,6 +103,6 @@ dhcpd.leases.man5: dhcpd.leases.5 -e "s#RUNDIR#$(VARRUN)#g" < dhcpd.leases.5 >dhcpd.leases.man5 dhcpd: $(OBJS) $(COBJ) $(DHCPLIB) - $(CC) $(LFLAGS) -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS) + $(CC) -pie $(LFLAGS) -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS) -lcap # Dependencies (semi-automatically-generated) diff --git a/server/confpars.c b/server/confpars.c index cb12397..e658edd 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -1013,10 +1013,13 @@ void parse_failover_peer (cfile, group, type) parse_warn (cfile, "peer address may not be omitted"); /* XXX - when/if we get a port number assigned, just set as default */ + /* See http://bugzilla.redhat.com/show_bug.cgi?id=167292 + * IANA registration by Bernard Volz + */ if (!peer -> me.port) - parse_warn (cfile, "local port may not be omitted"); + peer -> me.port = 647; if (!peer -> partner.port) - parse_warn (cfile, "peer port may not be omitted"); + peer -> partner.port = 847; if (peer -> i_am == primary) { if (!peer -> hba) { diff --git a/server/ddns.c b/server/ddns.c index 7c2df4b..83e1e74 100644 --- a/server/ddns.c +++ b/server/ddns.c @@ -499,7 +499,7 @@ int ddns_updates (struct packet *packet, ddns_rev_name.data = ddns_rev_name.buffer -> data; /* %Audit% Cannot exceed 17 bytes. %2004.06.17,Safe% */ - sprintf ((char *)ddns_rev_name.buffer -> data, + snprintf ((char *)ddns_rev_name.buffer -> data, 17, "%u.%u.%u.%u.", lease -> ip_addr . iabuf[3] & 0xff, lease -> ip_addr . iabuf[2] & 0xff, @@ -721,7 +721,7 @@ int ddns_removals (struct lease *lease) try_rev: if (find_bound_string (&ddns_rev_name, lease -> scope, "ddns-rev-name")) { - if (ddns_remove_ptr(&ddns_rev_name) == NOERROR) { + if (ddns_remove_ptr(&ddns_rev_name) == (isc_result_t) NOERROR) { unset (lease -> scope, "ddns-rev-name"); if (client_updated) unset (lease -> scope, diff --git a/server/dhcp.c b/server/dhcp.c index f502b19..3dcb49d 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -81,7 +81,7 @@ void dhcp (packet) s = dhcp_type_names[packet->packet_type - 1]; } else { /* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */ - sprintf(typebuf, "type %d", packet->packet_type); + snprintf(typebuf, sizeof(typebuf), "type %d", packet->packet_type); s = typebuf; } @@ -447,7 +447,7 @@ void dhcprequest (packet, ms_nulltp, ip_lease) /* piaddr() should not return more than a 15 byte string. * safe. */ - sprintf (smbuf, " (%s)", piaddr (sip)); + snprintf (smbuf, sizeof(smbuf), " (%s)", piaddr (sip)); have_server_identifier = 1; } else smbuf [0] = 0; @@ -1800,6 +1800,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) host_reference (&host, h, MDL); } if (!host) { + if (hp) + host_dereference (&hp, MDL); find_hosts_by_haddr (&hp, packet -> raw -> htype, packet -> raw -> chaddr, diff --git a/server/dhcpd.8 b/server/dhcpd.8 index b63336a..8ff7b50 100644 --- a/server/dhcpd.8 +++ b/server/dhcpd.8 @@ -74,6 +74,14 @@ dhcpd - Dynamic Host Configuration Protocol Server .I trace-playback-file ] [ +.B -u +.I user +] +[ +.B -j +.I chroot-dir +] +[ .I if0 [ .I ...ifN @@ -239,6 +247,12 @@ using the \fB-lf\fR switch, so that the DHCP server doesn't wipe out your existing lease file with its test data. The DHCP server will refuse to operate in playback mode unless you specify an alternate lease file. +.PP +Upon startup, this version of the DHCP server will switch to a non-root +pseudo-user and enter a chroot jail. The default username (\fIdhcpd\fR) +and the default chroot jail directory path (\fI/var/lib/dhcp/dhcpd\fR) +may be overridden with the \fB-u\fR and \fB-j\fR options, respectively. +.PP .SH CONFIGURATION The syntax of the dhcpd.conf(5) file is discussed separately. This section should be used as an overview of the configuration process, @@ -746,3 +760,8 @@ Consortium. Version 3 of the DHCP server was funded by Nominum, Inc. Information about Internet Systems Consortium is available at .B http://www.isc.org/\fR. Information about Nominum can be found at \fBhttp://www.nominum.com/\fR. +.PP +This version of dhcpd has been modified for ALT Linux +.RB ( http://www.altlinux.com/ ). +In particular, the privilege reduction functionality and the \fB-u\fR +and \fB-j\fR options are Openwall/ALT Linux extensions. diff --git a/server/dhcpd.c b/server/dhcpd.c index 8deb8d0..977df25 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -226,6 +226,8 @@ char *traceinfile = (char *)0; char *traceoutfile = (char *)0; #endif + char *server_user = "dhcpd"; + char *server_jail = "/var/lib/dhcp/dhcpd"; /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 2 (stderr) are open. To do this, we assume that when we @@ -235,10 +237,12 @@ fd = open("/dev/null", O_RDWR); if (fd == 1) fd = open("/dev/null", O_RDWR); - if (fd == 2) + if (fd == 2) { + fd = open ("/dev/null", O_RDWR); log_perror = 0; /* No sense logging to /dev/null. */ - else if (fd != -1) - close(fd); + } + if (fd < 0) + log_fatal ("Can't open %s: %m", "/dev/null"); /* Set up the client classification system. */ classification_setup (); @@ -319,6 +324,14 @@ int main (argc, argv, envp) } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; + } else if (!strcmp (argv [i], "-u")) { + if (++i == argc) + usage(); + server_user = argv[i]; + } else if (!strcmp (argv [i], "-j")) { + if (++i == argc) + usage(); + server_jail = argv[i]; } else if (!strcmp (argv [i], "--version")) { log_info ("isc-dhcpd-%s", DHCP_VERSION); exit (0); @@ -366,9 +379,9 @@ int main (argc, argv, envp) if (!quiet) { log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info ("%s", copyright); + log_info ("%s", arr); + log_info ("%s", url); } else { quiet = 0; log_perror = 0; @@ -498,12 +511,6 @@ int main (argc, argv, envp) group_write_hook = group_writer; - /* Start up the database... */ - db_startup (lftest); - - if (lftest) - exit (0); - /* Discover all the network interfaces and initialize them. */ discover_interfaces (DISCOVER_SERVER); @@ -524,7 +531,6 @@ int main (argc, argv, envp) #if defined (TRACING) trace_seed_stash (trace_srandom, seed + cur_time); #endif - postdb_startup (); #ifndef DEBUG if (daemon) { @@ -555,14 +561,18 @@ int main (argc, argv, envp) /* Write new pid file. */ if ((i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0) { - sprintf(pbuf, "%d\n", (int) getpid()); - IGNORE_RET(write(i, pbuf, strlen(pbuf))); + snprintf(pbuf, sizeof(pbuf), "%d\n", (int) getpid()); + if (write(i, pbuf, strlen(pbuf)) != strlen(pbuf)) + log_fatal("Error writing pid file: %s: %m", + path_dhcpd_pid); close(i); } else { log_error("Can't create PID file %s: %m.", path_dhcpd_pid); } + dhcpd_priv_minimize (server_user, server_jail); + /* If we were requested to log to stdout on the command line, keep doing so; otherwise, stop. */ if (log_perror == -1) @@ -569,19 +569,25 @@ if (daemon) { /* Become session leader and get pid... */ + if (dup2 (fd, 0) != 0 || + dup2 (fd, 1) != 1 || + dup2 (fd, 2) != 2) + log_fatal("Can't daemonize: %m"); + close (fd); + fd = -1; pid = setsid(); - - /* Close standard I/O descriptors. */ - close(0); - close(1); - close(2); - - /* Reopen them on /dev/null. */ - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); - log_perror = 0; /* No sense logging to /dev/null. */ } + + /* Start up the database... */ + db_startup (lftest); + + if (lftest) + exit (0); + + postdb_startup (); + + dhcpd_priv_drop (server_user, server_jail); + #endif /* !DEBUG */ #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ @@ -788,9 +812,9 @@ void postconf_initialization (int quiet) log_perror = 0; log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); - log_info (url); + log_info ("%s", copyright); + log_info ("%s", arr); + log_info ("%s", url); log_perror = tmp; } } else @@ -862,11 +886,12 @@ void postdb_startup (void) static void usage () { log_info ("%s %s", message, DHCP_VERSION); - log_info (copyright); - log_info (arr); + log_info ("%s", copyright); + log_info ("%s", arr); - log_fatal ("Usage: dhcpd [-p ] [-d] [-f]%s%s%s%s", + log_fatal ("Usage: dhcpd [-p ] [-d] [-f]%s%s%s%s%s", "\n [-cf config-file] [-lf lease-file]", + "\n [-u user] [-j chroot-dir]", #if defined (TRACING) "\n [-tf trace-output-file]", "\n [-play trace-input-file]", diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index 04afd4e..ad29ebb 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -531,9 +531,9 @@ primary server might look like this: failover peer "foo" { primary; address anthrax.rc.vix.com; - port 519; + port 647; peer address trantor.rc.vix.com; - peer port 520; + peer port 847; max-response-delay 60; max-unacked-updates 10; mclt 3600; @@ -592,9 +592,7 @@ statement .B port \fIport-number\fR\fB;\fR .PP The \fBport\fR statement declares the TCP port on which the server -should listen for connections from its failover peer. This statement -may not currently be omitted, because the failover protocol does not -yet have a reserved TCP port number. +should listen for connections from its failover peer. .RE .PP The @@ -606,10 +604,8 @@ statement .PP The \fBpeer port\fR statement declares the TCP port to which the server should connect to reach its failover peer for failover -messages. This statement may not be omitted because the failover -protocol does not yet have a reserved TCP port number. The port -number declared in the \fBpeer port\fR statement may be the same as -the port number declared in the \fBport\fR statement. +messages. The port number declared in the \fBpeer port\fR statement +may be the same as the port number declared in the \fBport\fR statement. .RE .PP The @@ -2038,8 +2034,8 @@ The syntax of the \fIsyslog.conf\fR file may be different on some operating systems - consult the \fIsyslog.conf\fR manual page to be sure. To get syslog to start logging to the new file, you must first create the file with correct ownership and permissions (usually, the -same owner and permissions of your /var/log/messages or -/usr/adm/messages file should be fine) and send a SIGHUP to syslogd. +same owner and permissions of your /var/log/messages +file should be fine) and send a SIGHUP to syslogd. Some systems support log rollover using a shell script or program called newsyslog or logrotate, and you may be able to configure this as well so that your log file doesn't grow uncontrollably. @@ -2114,7 +2110,8 @@ statement The \fInext-server\fR statement is used to specify the host address of the server from which the initial boot file (specified in the \fIfilename\fR statement) is to be loaded. \fIServer-name\fR should -be a numeric IP address or a domain name. +be a numeric IP address or a domain name. If no \fInext-server\fR +statement applies to a given client, the address 0.0.0.0 is used. .RE .PP The diff --git a/server/failover.c b/server/failover.c index 1be6c04..8dca575 100644 --- a/server/failover.c +++ b/server/failover.c @@ -3615,7 +3615,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, val = va_arg (va, unsigned); #if defined (DEBUG_FAILOVER_MESSAGES) /* %Audit% Cannot exceed 24 bytes. %2004.06.17,Safe% */ - sprintf (tbuf, " %d", val); + snprintf (tbuf, sizeof(tbuf), " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif option.data [i + 4] = val; @@ -3635,7 +3635,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 17 bytes. %2004.06.17,Safe%*/ - sprintf (tbuf, " %u.%u.%u.%u", + snprintf (tbuf, sizeof(tbuf), " %u.%u.%u.%u", iaddr [0], iaddr [1], iaddr [2], iaddr [3]); failover_print (obuf, obufix, obufmax, tbuf); #endif @@ -3648,7 +3648,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, val = va_arg (va, unsigned); #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ - sprintf (tbuf, " %d", val); + snprintf (tbuf, sizeof(tbuf), " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif putULong (&option.data [4 + i * 4], val); @@ -3661,7 +3661,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, #if defined (DEBUG_FAILOVER_MESSAGES) for (i = 0; i < count; i++) { /* 23 bytes plus nul, safe. */ - sprintf (tbuf, " %d", bval [i]); + snprintf (tbuf, sizeof(tbuf), " %d", bval [i]); failover_print (obuf, obufix, obufmax, tbuf); } #endif @@ -3699,7 +3699,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, #if defined (DEBUG_FAILOVER_MESSAGES) for (i = 4; i < size; i++) { /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ - sprintf (tbuf, " %d", option.data [i]); + snprintf (tbuf, sizeof(tbuf), " %d", option.data [i]); failover_print (obuf, obufix, obufmax, tbuf); } #endif @@ -3710,7 +3710,7 @@ failover_option_t *dhcp_failover_make_option (unsigned code, val = va_arg (va, u_int32_t); #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ - sprintf (tbuf, " %d", val); + snprintf (tbuf, sizeof(tbuf), " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif putUShort (&option.data [4 + i * 2], val); diff --git a/server/omapi.c b/server/omapi.c index c87f05b..f807c5d 100644 --- a/server/omapi.c +++ b/server/omapi.c @@ -1186,7 +1186,7 @@ isc_result_t dhcp_host_signal_handler (omapi_object_t *h, if (!host -> name) { char hnbuf [64]; - sprintf (hnbuf, "nh%08lx%08lx", + snprintf (hnbuf, sizeof(hnbuf), "nh%08lx%08lx", (unsigned long)cur_time, (unsigned long)host); host -> name = dmalloc (strlen (hnbuf) + 1, MDL); if (!host -> name)