ndhc/leasefile.c

97 lines
3.2 KiB
C
Raw Normal View History

// Copyright 2011-2022 Nicholas J. Kain <njkain at gmail dot com>
// SPDX-License-Identifier: MIT
2011-04-20 02:07:43 +05:30
#include <stdlib.h>
#include <stdio.h>
2011-04-20 02:07:43 +05:30
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
2014-03-31 02:32:48 +05:30
#include "nk/log.h"
#include "nk/io.h"
2014-03-11 05:12:52 +05:30
#include "leasefile.h"
#include "ndhc.h"
Support running an executable file when a new lease is acquired. If no 'script-file = SCRIPTFILE' is specified in the configuration file and if no '-X SCRIPTFILE' or '--script-file SCRIPTFILE' command argument is provided, then this functionality is entirely inactive and no associated subprocess is spawned. Otherwise, ndhc will spawn a subprocess that runs as root that has the sole job of forking off a subprocess that exec's the specified script in a sanitized and fixed-state environment whenever a new DHCPv4 lease is acquired. Note that this script is provided no information about ndhc or the DHCP state in the environment or in any argument fields; it is the responsibility of this script to gather whatever information it needs from either the filesystem or syscalls. This design is intended to avoid the historical problems that are associated with dhcp clients invoking scripts. The path of the scriptfile cannot be changed after ndhc is initially run; ndhc forks off the privsep script subprocess that executes scripts after it has read the configuration file and command arguments, but before it begins processing network data; thus, it is impossible for the network-handling process to modify or influence the script assuming proper OS memory protection. The privsep channel communicates that the script should be run by simply writing a newline; anything else will result in ndhc terminating itself. Before the recommended way to update system state after a change in lease information was to run the fcactus program and watch the associated leasefile for the interface for modification; now no external program is needed for this job.
2022-02-24 11:22:26 +05:30
#include "scriptd.h"
2011-04-20 02:07:43 +05:30
static int leasefilefd = -1;
static void get_leasefile_path(char *leasefile, size_t dlen, char *ifname)
2011-04-20 02:07:43 +05:30
{
char *p = memccpy(leasefile, state_dir, 0, dlen);
if (!p) suicide("%s: (%s) memccpy failed", client_config.interface, __func__);
p = memccpy(p - 1, "/LEASE-", 0, dlen - (size_t)(p - leasefile - 1));
if (!p) suicide("%s: (%s) memccpy failed", client_config.interface, __func__);
p = memccpy(p - 1, ifname, 0, dlen - (size_t)(p - leasefile - 1));
if (!p) suicide("%s: (%s) memccpy failed", client_config.interface, __func__);
2011-04-20 02:07:43 +05:30
}
2014-03-11 05:12:52 +05:30
void open_leasefile(void)
2011-04-20 02:07:43 +05:30
{
char leasefile[PATH_MAX];
get_leasefile_path(leasefile, sizeof leasefile, client_config.interface);
leasefilefd = open(leasefile, O_WRONLY|O_CREAT|O_CLOEXEC, 0644);
if (leasefilefd < 0)
2020-11-07 05:17:51 +05:30
suicide("%s: (%s) Failed to create lease file '%s': %s",
client_config.interface, __func__, leasefile, strerror(errno));
2011-04-20 02:07:43 +05:30
}
Support running an executable file when a new lease is acquired. If no 'script-file = SCRIPTFILE' is specified in the configuration file and if no '-X SCRIPTFILE' or '--script-file SCRIPTFILE' command argument is provided, then this functionality is entirely inactive and no associated subprocess is spawned. Otherwise, ndhc will spawn a subprocess that runs as root that has the sole job of forking off a subprocess that exec's the specified script in a sanitized and fixed-state environment whenever a new DHCPv4 lease is acquired. Note that this script is provided no information about ndhc or the DHCP state in the environment or in any argument fields; it is the responsibility of this script to gather whatever information it needs from either the filesystem or syscalls. This design is intended to avoid the historical problems that are associated with dhcp clients invoking scripts. The path of the scriptfile cannot be changed after ndhc is initially run; ndhc forks off the privsep script subprocess that executes scripts after it has read the configuration file and command arguments, but before it begins processing network data; thus, it is impossible for the network-handling process to modify or influence the script assuming proper OS memory protection. The privsep channel communicates that the script should be run by simply writing a newline; anything else will result in ndhc terminating itself. Before the recommended way to update system state after a change in lease information was to run the fcactus program and watch the associated leasefile for the interface for modification; now no external program is needed for this job.
2022-02-24 11:22:26 +05:30
static void do_write_leasefile(struct in_addr ipnum)
2011-04-20 02:07:43 +05:30
{
char ip[INET_ADDRSTRLEN];
char out[INET_ADDRSTRLEN*2];
if (leasefilefd < 0) {
log_line("%s: (%s) leasefile fd < 0; no leasefile will be written",
client_config.interface, __func__);
2011-04-20 02:07:43 +05:30
return;
}
2011-04-20 02:07:43 +05:30
inet_ntop(AF_INET, &ipnum, ip, sizeof ip);
char *p = memccpy(out, ip, 0, sizeof out);
if (!p) {
log_line("%s: (%s) memccpy failed", client_config.interface, __func__);
return;
}
p = memccpy(p - 1, "\n", 0, sizeof out - (size_t)(p - out - 1));
if (!p) {
log_line("%s: (%s) memccpy failed", client_config.interface, __func__);
return;
}
size_t outlen = strlen(out);
// Make sure that we're not overwriting the leasefile with an invalid
// IP address. This is a very minimal check.
if (outlen < 7) return;
2020-11-07 05:17:51 +05:30
if (safe_ftruncate(leasefilefd, 0)) {
log_line("%s: (%s) Failed to truncate lease file: %s",
client_config.interface, __func__, strerror(errno));
2020-11-07 05:17:51 +05:30
return;
}
if (lseek(leasefilefd, 0, SEEK_SET) == (off_t)-1) {
log_line("%s: (%s) Failed to seek to start of lease file: %s",
client_config.interface, __func__, strerror(errno));
2020-11-07 05:17:51 +05:30
return;
2011-04-20 02:07:43 +05:30
}
2020-11-07 05:17:51 +05:30
ssize_t ret = safe_write(leasefilefd, out, outlen);
if (ret < 0 || (size_t)ret != outlen)
log_line("%s: (%s) Failed to write ip to lease file.",
client_config.interface, __func__);
else
fsync(leasefilefd);
2011-04-20 02:07:43 +05:30
}
2013-05-06 16:37:54 +05:30
Support running an executable file when a new lease is acquired. If no 'script-file = SCRIPTFILE' is specified in the configuration file and if no '-X SCRIPTFILE' or '--script-file SCRIPTFILE' command argument is provided, then this functionality is entirely inactive and no associated subprocess is spawned. Otherwise, ndhc will spawn a subprocess that runs as root that has the sole job of forking off a subprocess that exec's the specified script in a sanitized and fixed-state environment whenever a new DHCPv4 lease is acquired. Note that this script is provided no information about ndhc or the DHCP state in the environment or in any argument fields; it is the responsibility of this script to gather whatever information it needs from either the filesystem or syscalls. This design is intended to avoid the historical problems that are associated with dhcp clients invoking scripts. The path of the scriptfile cannot be changed after ndhc is initially run; ndhc forks off the privsep script subprocess that executes scripts after it has read the configuration file and command arguments, but before it begins processing network data; thus, it is impossible for the network-handling process to modify or influence the script assuming proper OS memory protection. The privsep channel communicates that the script should be run by simply writing a newline; anything else will result in ndhc terminating itself. Before the recommended way to update system state after a change in lease information was to run the fcactus program and watch the associated leasefile for the interface for modification; now no external program is needed for this job.
2022-02-24 11:22:26 +05:30
void write_leasefile(struct in_addr ipnum)
{
do_write_leasefile(ipnum);
request_scriptd_run();
if (client_config.enable_s6_notify) {
static char buf[] = "\n";
safe_write(client_config.s6_notify_fd, buf, 1);
close(client_config.s6_notify_fd);
client_config.enable_s6_notify = false;
}
}