* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: util.c,v 1.2.2.2.4.3.2.1 2002/03/31 21:01:33 jrjackson Exp $
+ * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $
*/
#include "amanda.h"
#include "util.h"
+#include <regex.h>
+#include "arglist.h"
+#include "clock.h"
+#include "sockaddr-util.h"
+#include "conffile.h"
+
+#ifdef HAVE_LIBCURL
+#include <curl/curl.h>
+#endif
+
+static int make_socket(sa_family_t family);
+static int connect_port(struct sockaddr_storage *addrp, in_port_t port, char *proto,
+ struct sockaddr_storage *svaddr, int nonblock);
/*
* Keep calling read() until we've read buflen's worth of data, or EOF,
* Returns the number of bytes read, 0 on EOF, or negative on error.
*/
ssize_t
-fullread(fd, vbuf, buflen)
- int fd;
- void *vbuf;
- size_t buflen;
+fullread(
+ int fd,
+ void * vbuf,
+ size_t buflen)
{
ssize_t nread, tot = 0;
char *buf = vbuf; /* cast to char so we can ++ it */
while (buflen > 0) {
nread = read(fd, buf, buflen);
- if (nread < 0)
- return (nread);
+ if (nread < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ return ((tot > 0) ? tot : -1);
+ }
+
if (nread == 0)
break;
+
tot += nread;
buf += nread;
buflen -= nread;
* Returns the number of bytes written, or negative on error.
*/
ssize_t
-fullwrite(fd, vbuf, buflen)
- int fd;
- const void *vbuf;
- size_t buflen;
+fullwrite(
+ int fd,
+ const void *vbuf,
+ size_t buflen)
{
ssize_t nwritten, tot = 0;
const char *buf = vbuf; /* cast to char so we can ++ it */
while (buflen > 0) {
nwritten = write(fd, buf, buflen);
- if (nwritten < 0)
- return (nwritten);
+ if (nwritten < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ return ((tot > 0) ? tot : -1);
+ }
tot += nwritten;
buf += nwritten;
buflen -= nwritten;
return (tot);
}
+static int
+make_socket(
+ sa_family_t family)
+{
+ int s;
+ int save_errno;
+#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
+ int on=1;
+ int r;
+#endif
+
+ s = socket(family, SOCK_STREAM, 0);
+ if (s == -1) {
+ save_errno = errno;
+ dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
+ errno = save_errno;
+ return -1;
+ }
+ if (s < 0 || s >= (int)FD_SETSIZE) {
+ aclose(s);
+ errno = EMFILE; /* out of range */
+ return -1;
+ }
+
+#ifdef USE_REUSEADDR
+ r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (r < 0) {
+ save_errno = errno;
+ dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
+ strerror(errno));
+ errno = save_errno;
+ }
+#endif
+
+#ifdef SO_KEEPALIVE
+ r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ (void *)&on, SIZEOF(on));
+ if (r == -1) {
+ save_errno = errno;
+ dbprintf(_("make_socket: setsockopt() failed: %s\n"),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ return -1;
+ }
+#endif
+
+ return s;
+}
+
+/* addrp is my address */
+/* svaddr is the address of the remote machine */
+/* return socket on success */
+/* return -1 on failure */
+int
+connect_portrange(
+ struct sockaddr_storage *addrp,
+ in_port_t first_port,
+ in_port_t last_port,
+ char * proto,
+ struct sockaddr_storage *svaddr,
+ int nonblock)
+{
+ int s;
+ in_port_t port;
+ static in_port_t port_in_use[1024];
+ static int nb_port_in_use = 0;
+ int i;
+ int save_errno = EAGAIN;
+
+ assert(first_port <= last_port);
+ /* Try a port already used */
+ for(i=0; i < nb_port_in_use; i++) {
+ port = port_in_use[i];
+ if(port >= first_port && port <= last_port) {
+ s = connect_port(addrp, port, proto, svaddr, nonblock);
+ if(s == -2) return -1;
+ if(s > 0) {
+ return s;
+ }
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
+ }
+ }
+
+ /* Try a port in the range */
+ for (port = first_port; port <= last_port; port++) {
+ s = connect_port(addrp, port, proto, svaddr, nonblock);
+ if(s == -2) return -1;
+ if(s > 0) {
+ port_in_use[nb_port_in_use++] = port;
+ return s;
+ }
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
+ }
+
+ dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
+ first_port,
+ last_port);
+ errno = save_errno;
+ return -1;
+}
+
+/* addrp is my address */
+/* svaddr is the address of the remote machine */
+/* return -2: Don't try again */
+/* return -1: Try with another port */
+/* return >0: this is the connected socket */
+int
+connect_port(
+ struct sockaddr_storage *addrp,
+ in_port_t port,
+ char * proto,
+ struct sockaddr_storage *svaddr,
+ int nonblock)
+{
+ int save_errno;
+ struct servent * servPort;
+ socklen_t len;
+ socklen_t socklen;
+ int s;
+
+ servPort = getservbyport((int)htons(port), proto);
+ if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
+ dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
+ port, servPort->s_name);
+ errno = EBUSY;
+ return -1;
+ }
+
+ if ((s = make_socket(addrp->ss_family)) == -1) return -2;
+
+ SS_SET_PORT(addrp, port);
+ socklen = SS_LEN(addrp);
+ if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
+ save_errno = errno;
+ aclose(s);
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - %s\n"),
+ port, strerror(errno));
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
+ port, servPort->s_name, strerror(errno));
+ }
+ if (save_errno != EADDRINUSE) {
+ errno = save_errno;
+ return -2;
+ }
+
+ errno = save_errno;
+ return -1;
+ }
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
+ port, servPort->s_name);
+ }
+
+ /* find out what port was actually used */
+
+ len = sizeof(*addrp);
+ if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
+ save_errno = errno;
+ dbprintf(_("connect_port: getsockname() failed: %s\n"),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ return -1;
+ }
+
+ if (nonblock)
+ fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
+ if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
+ save_errno = errno;
+ dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
+ str_sockaddr(addrp),
+ strerror(save_errno));
+ dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
+ str_sockaddr(svaddr),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ if (save_errno == ECONNREFUSED ||
+ save_errno == EHOSTUNREACH ||
+ save_errno == ENETUNREACH ||
+ save_errno == ETIMEDOUT) {
+ return -2 ;
+ }
+ return -1;
+ }
+
+ dbprintf(_("connected to %s\n"),
+ str_sockaddr(svaddr));
+ dbprintf(_("our side is %s\n"),
+ str_sockaddr(addrp));
+ return s;
+}
+
+
/*
* Bind to a port in the given range. Takes a begin,end pair of port numbers.
*
* on success.
*/
int
-bind_portrange(s, addrp, first_port, last_port)
- int s;
- struct sockaddr_in *addrp;
- int first_port, last_port;
+bind_portrange(
+ int s,
+ struct sockaddr_storage *addrp,
+ in_port_t first_port,
+ in_port_t last_port,
+ char * proto)
{
- int port, cnt;
- const int num_ports = last_port - first_port + 1;
- int save_errno;
+ in_port_t port;
+ in_port_t cnt;
+ socklen_t socklen;
+ struct servent *servPort;
+ const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
+ int save_errno = EAGAIN;
- assert(first_port > 0 && first_port <= last_port && last_port < 65536);
+ assert(first_port <= last_port);
/*
* We pick a different starting port based on our pid and the current
* time to avoid always picking the same reserved port twice.
*/
- port = ((getpid() + time(0)) % num_ports) + first_port;
+ port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
/*
- * Scan through the range, trying all available ports. Wrap around
+ * Scan through the range, trying all available ports that are either
+ * not taken in /etc/services or registered for *amanda*. Wrap around
* if we don't happen to start at the beginning.
*/
for (cnt = 0; cnt < num_ports; cnt++) {
- addrp->sin_port = htons(port);
- if (bind(s, (struct sockaddr *)addrp, sizeof(*addrp)) >= 0)
- return 0;
- /*
- * If the error was something other then port in use, stop.
- */
- if (errno != EADDRINUSE)
- break;
+ servPort = getservbyport((int)htons(port), proto);
+ if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
+ SS_SET_PORT(addrp, port);
+ socklen = SS_LEN(addrp);
+ if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
+ if (servPort == NULL) {
+ dbprintf(_("bind_portrange2: Try port %d: Available - Success\n"), port);
+ } else {
+ dbprintf(_("bind_portrange2: Try port %d: Owned by %s - Success.\n"), port, servPort->s_name);
+ }
+ return 0;
+ }
+ if (errno != EAGAIN && errno != EBUSY)
+ save_errno = errno;
+ if (servPort == NULL) {
+ dbprintf(_("bind_portrange2: Try port %d: Available - %s\n"),
+ port, strerror(errno));
+ } else {
+ dbprintf(_("bind_portrange2: Try port %d: Owned by %s - %s\n"),
+ port, servPort->s_name, strerror(errno));
+ }
+ } else {
+ dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),
+ port, servPort->s_name);
+ }
if (++port > last_port)
port = first_port;
}
- if (cnt == num_ports) {
- dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n",
- debug_prefix_time(NULL),
+ dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),
first_port,
- last_port));
- errno = EAGAIN;
- } else if (last_port < IPPORT_RESERVED
- && getuid() != 0
- && errno == EACCES) {
+ last_port);
+ errno = save_errno;
+ return -1;
+}
+
+
+int
+needs_quotes(
+ const char * str)
+{
+ return (match("[ \t\f\r\n\"]", str) != 0);
+}
+
+
+/*
+ * For backward compatibility we are trying for minimal quoting.
+ * We only quote a string if it contains whitespace or is misquoted...
+ */
+
+char *
+quote_string(
+ const char *str)
+{
+ char * s;
+ char * ret;
+
+ if ((str == NULL) || (*str == '\0')) {
+ ret = stralloc("\"\"");
+ } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
+ /*
+ * String does not need to be quoted since it contains
+ * neither whitespace, control or quote characters.
+ */
+ ret = stralloc(str);
+ } else {
/*
- * Do not bother with an error message in this case because it
- * is expected.
+ * Allocate maximum possible string length.
+ * (a string of all quotes plus room for leading ", trailing " and NULL)
*/
+ ret = s = alloc((strlen(str) * 2) + 2 + 1);
+ *(s++) = '"';
+ while (*str != '\0') {
+ if (*str == '\t') {
+ *(s++) = '\\';
+ *(s++) = 't';
+ str++;
+ continue;
+ } else if (*str == '\n') {
+ *(s++) = '\\';
+ *(s++) = 'n';
+ str++;
+ continue;
+ } else if (*str == '\r') {
+ *(s++) = '\\';
+ *(s++) = 'r';
+ str++;
+ continue;
+ } else if (*str == '\f') {
+ *(s++) = '\\';
+ *(s++) = 'f';
+ str++;
+ continue;
+ } else if (*str == '\\') {
+ *(s++) = '\\';
+ *(s++) = '\\';
+ str++;
+ continue;
+ }
+ if (*str == '"')
+ *(s++) = '\\';
+ *(s++) = *(str++);
+ }
+ *(s++) = '"';
+ *s = '\0';
+ }
+ return (ret);
+}
+
+
+char *
+unquote_string(
+ const char *str)
+{
+ char * ret;
+
+ if ((str == NULL) || (*str == '\0')) {
+ ret = stralloc("");
+ } else {
+ char * in;
+ char * out;
+
+ ret = in = out = stralloc(str);
+ while (*in != '\0') {
+ if (*in == '"') {
+ in++;
+ continue;
+ }
+
+ if (*in == '\\') {
+ in++;
+ if (*in == 'n') {
+ in++;
+ *(out++) = '\n';
+ continue;
+ } else if (*in == 't') {
+ in++;
+ *(out++) = '\t';
+ continue;
+ } else if (*in == 'r') {
+ in++;
+ *(out++) = '\r';
+ continue;
+ } else if (*in == 'f') {
+ in++;
+ *(out++) = '\f';
+ continue;
+ }
+ }
+ *(out++) = *(in++);
+ }
+ *out = '\0';
+ }
+ return (ret);
+}
+
+char *
+sanitize_string(
+ const char *str)
+{
+ char * s;
+ char * ret;
+
+ if ((str == NULL) || (*str == '\0')) {
+ ret = stralloc("");
} else {
+ ret = stralloc(str);
+ for (s = ret; *s != '\0'; s++) {
+ if (iscntrl((int)*s))
+ *s = '?';
+ }
+ }
+ return (ret);
+}
+
+/*
+ Return 0 if the following characters are present
+ * ( ) < > [ ] , ; : ! $ \ / "
+ else returns 1
+*/
+
+int
+validate_mailto(
+ const char *mailto)
+{
+ return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
+}
+
+int copy_file(
+ char *dst,
+ char *src,
+ char **errmsg)
+{
+ int infd, outfd;
+ int save_errno;
+ ssize_t nb;
+ char buf[32768];
+ char *quoted;
+
+ if ((infd = open(src, O_RDONLY)) == -1) {
save_errno = errno;
- dbprintf(("%s: bind_portrange: port %d: %s\n",
- debug_prefix_time(NULL),
- port,
- strerror(errno)));
- errno = save_errno;
+ quoted = quote_string(src);
+ *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
+ quoted, strerror(save_errno));
+ amfree(quoted);
+ return -1;
}
- return -1;
+
+ if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
+ save_errno = errno;
+ quoted = quote_string(dst);
+ *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
+ quoted, strerror(save_errno));
+ amfree(quoted);
+ close(infd);
+ return -1;
+ }
+
+ while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
+ if(fullwrite(outfd,&buf,(size_t)nb) < nb) {
+ save_errno = errno;
+ quoted = quote_string(dst);
+ *errmsg = vstrallocf(_("Error writing to '%s': %s"),
+ quoted, strerror(save_errno));
+ amfree(quoted);
+ close(infd);
+ close(outfd);
+ return -1;
+ }
+ }
+
+ if (nb < 0) {
+ save_errno = errno;
+ quoted = quote_string(src);
+ *errmsg = vstrallocf(_("Error reading from '%s': %s"),
+ quoted, strerror(save_errno));
+ amfree(quoted);
+ close(infd);
+ close(outfd);
+ return -1;
+ }
+
+ close(infd);
+ close(outfd);
+ return 0;
}
+#ifndef HAVE_READLINE
/*
- * Construct a datestamp (YYYYMMDD) from a time_t.
+ * simple readline() replacements, used when we don't have readline
+ * support from the system.
*/
+
char *
-construct_datestamp(t)
- time_t *t;
+readline(
+ const char *prompt)
{
- struct tm *tm;
- char datestamp[3*NUM_STR_SIZE];
- time_t when;
+ g_printf("%s", prompt);
+ fflush(stdout);
+ fflush(stderr);
+ return agets(stdin);
+}
+
+void
+add_history(
+ const char *line)
+{
+ (void)line; /* Quiet unused parameter warning */
+}
+
+#endif
+
+/* Order of preference: readdir64(), readdir(). */
+#if HAVE_DECL_READDIR64
+# define USE_DIRENT64
+# define USE_READDIR64
+#elif HAVE_DECL_READDIR
+# define USE_READDIR
+#else
+# error No readdir() or readdir64() available!
+#endif
+
+char * portable_readdir(DIR* handle) {
+
+#ifdef USE_DIRENT64
+ struct dirent64 *entry_p;
+#else
+ struct dirent *entry_p;
+#endif
+
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ g_static_mutex_lock(&mutex);
+
+#ifdef USE_READDIR
+ entry_p = readdir(handle);
+#endif
+#ifdef USE_READDIR64
+ entry_p = readdir64(handle);
+#endif
+
+ g_static_mutex_unlock(&mutex);
+
+ if (entry_p == NULL)
+ return NULL;
+
+ /* FIXME: According to glibc documentation, d_name may not be
+ null-terminated in some cases on some very old platforms. Not
+ sure what to do about that case. */
+ return strdup(entry_p->d_name);
+}
- if(t == NULL) {
- when = time((time_t *)NULL);
+int search_directory(DIR * handle, const char * regex,
+ SearchDirectoryFunctor functor, gpointer user_data) {
+ int rval = 0;
+ regex_t compiled_regex;
+ gboolean done = FALSE;
+
+ if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
+ regfree(&compiled_regex);
+ return -1;
+ }
+
+ rewinddir(handle);
+
+ while (!done) {
+ char * read_name;
+ int result;
+ read_name = portable_readdir(handle);
+ if (read_name == NULL) {
+ regfree(&compiled_regex);
+ return rval;
+ }
+ result = regexec(&compiled_regex, read_name, 0, NULL, 0);
+ if (result == 0) {
+ rval ++;
+ done = !functor(read_name, user_data);
+ }
+ amfree(read_name);
+ }
+ regfree(&compiled_regex);
+ return rval;
+}
+
+char* find_regex_substring(const char* base_string, const regmatch_t match) {
+ char * rval;
+ int size;
+
+ size = match.rm_eo - match.rm_so;
+ rval = malloc(size+1);
+ memcpy(rval, base_string + match.rm_so, size);
+ rval[size] = '\0';
+
+ return rval;
+}
+
+int compare_possibly_null_strings(const char * a, const char * b) {
+ if (a == b) {
+ /* NULL or otherwise, they're the same. */
+ return 0;
+ } else if (a == NULL) {
+ /* b != NULL */
+ return -1;
+ } else if (b == NULL) {
+ /* a != NULL */
+ return 1;
} else {
- when = *t;
+ /* a != NULL != b */
+ return strcmp(a, b);
}
- tm = localtime(&when);
- ap_snprintf(datestamp, sizeof(datestamp),
- "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
- return stralloc(datestamp);
}
-/*
- * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
- */
+gboolean amanda_thread_init(void) {
+ gboolean success = FALSE;
+#ifdef HAVE_LIBCURL
+ static gboolean did_curl_init = FALSE;
+ if (!did_curl_init) {
+# ifdef G_THREADS_ENABLED
+ g_assert(!g_thread_supported());
+# endif
+ g_assert(curl_global_init(CURL_GLOBAL_ALL) == 0);
+ did_curl_init = TRUE;
+ }
+#endif
+#if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
+ if (g_thread_supported()) {
+ return TRUE;
+ }
+ g_thread_init(NULL);
+ success = TRUE;
+#endif
+ return success;
+}
+
+int
+resolve_hostname(const char *hostname,
+ int socktype,
+ struct addrinfo **res,
+ char **canonname)
+{
+ struct addrinfo hints;
+ struct addrinfo *myres;
+ int flags = 0;
+ int result;
+
+ if (res) *res = NULL;
+ if (canonname) {
+ *canonname = NULL;
+ flags = AI_CANONNAME;
+ }
+
+#ifdef AI_ADDRCONFIG
+ flags |= AI_ADDRCONFIG;
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = flags;
+ hints.ai_socktype = socktype;
+ result = getaddrinfo(hostname, NULL, &hints, &myres);
+ if (result != 0) {
+ return result;
+ }
+
+ if (canonname && myres && myres->ai_canonname) {
+ *canonname = stralloc(myres->ai_canonname);
+ }
+
+ if (res) {
+ *res = myres;
+ } else {
+ freeaddrinfo(myres);
+ }
+
+ return result;
+}
+
char *
-construct_timestamp(t)
- time_t *t;
+_str_exit_status(
+ char *subject,
+ amwait_t status)
+{
+ if (WIFEXITED(status)) {
+ int exitstatus = WEXITSTATUS(status);
+ if (exitstatus == 0)
+ return vstrallocf(_("%s exited normally"), subject);
+ else
+ return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signal = WTERMSIG(status);
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status))
+ return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
+ subject, signal);
+ else
+#endif
+ return vstrallocf(_("%s exited after receiving signal %d"),
+ subject, signal);
+ }
+
+ if (WIFSTOPPED(status)) {
+ int signal = WSTOPSIG(status);
+ return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
+ subject, signal);
+ }
+
+#ifdef WIFCONTINUED
+ if (WIFCONTINUED(status)) {
+ return vstrallocf(_("%s was resumed"), subject);
+ }
+#endif
+
+ return vstrallocf(_("%s exited in unknown circumstances"), subject);
+}
+
+void
+check_running_as(running_as_flags who)
{
- struct tm *tm;
- char timestamp[6*NUM_STR_SIZE];
- time_t when;
+#ifdef CHECK_USERID
+ struct passwd *pw;
+ uid_t uid_me;
+ uid_t uid_target;
+ char *uname_me = NULL;
+ char *uname_target = NULL;
+ char *dumpuser;
+
+ uid_me = getuid();
+ if ((pw = getpwuid(uid_me)) == NULL) {
+ error(_("current userid %ld not found in password database"), (long)uid_me);
+ /* NOTREACHED */
+ }
+ uname_me = stralloc(pw->pw_name);
+
+#ifndef SINGLE_USERID
+ if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
+ error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
+ (long long int)geteuid(), (long long int)uid_me);
+ /* NOTREACHED */
+ }
+#endif
+
+ switch (who & RUNNING_AS_USER_MASK) {
+ case RUNNING_AS_ROOT:
+ uid_target = 0;
+ uname_target = "root";
+ break;
+
+ case RUNNING_AS_DUMPUSER_PREFERRED:
+ dumpuser = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(dumpuser)) != NULL &&
+ uid_me != pw->pw_uid) {
+ if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
+ uid_me == pw->pw_uid) {
+ /* uid == CLIENT_LOGIN: not ideal, but OK */
+ dbprintf(_("NOTE: running as '%s', which is the client"
+ " user, not the dumpuser ('%s'); forging"
+ " on anyway\n"),
+ CLIENT_LOGIN, dumpuser);
+ uid_target = uid_me; /* force success below */
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case RUNNING_AS_DUMPUSER:
+ uname_target = getconf_str(CNF_DUMPUSER);
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up dumpuser \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
- if(t == NULL) {
- when = time((time_t *)NULL);
+ case RUNNING_AS_CLIENT_LOGIN:
+ uname_target = CLIENT_LOGIN;
+ if ((pw = getpwnam(uname_target)) == NULL) {
+ error(_("cannot look up client user \"%s\""), uname_target);
+ /*NOTREACHED*/
+ }
+ uid_target = pw->pw_uid;
+ break;
+
+ default:
+ error(_("Unknown check_running_as() call"));
+ /* NOTREACHED */
+ }
+
+ if (uid_me != uid_target) {
+ error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
+ /*NOTREACHED*/
+ }
+ amfree(uname_me);
+
+#else
+ /* Quiet unused variable warning */
+ (void)who;
+#endif
+}
+
+int
+set_root_privs(int need_root)
+{
+#ifndef SINGLE_USERID
+ if (need_root) {
+ if (seteuid(0) == -1) return 0;
+ /* (we don't switch the group back) */
} else {
- when = *t;
+ if (geteuid() != 0) return 0;
+ if (seteuid(getuid()) == -1) return 0;
+ if (setegid(getgid()) == -1) return 0;
}
- tm = localtime(&when);
- ap_snprintf(timestamp, sizeof(timestamp),
- "%04d%02d%02d%02d%02d%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- return stralloc(timestamp);
+#else
+ (void)need_root; /* Quiet unused variable warning */
+#endif
+ return 1;
+}
+
+int
+become_root(void)
+{
+#ifndef SINGLE_USERID
+ if (setuid(0) == -1) return 0;
+#endif
+ return 1;
}
+
+/*
+ * Process parameters
+ */
+
+/* current process name */
+#define MAX_PNAME 128
+static char pname[MAX_PNAME] = "unknown";
+
+void
+set_pname(char *p)
+{
+ g_strlcpy(pname, p, sizeof(pname));
+}
+
+char *
+get_pname(void)
+{
+ return pname;
+}
+