/*
* util.c:
* Various utility functions for tpop3d.
*
* Copyright (c) 2001 Chris Lightfoot. All rights reserved.
*
*/
static const char rcsid[] = "$Id: util.c,v 1.24 2003/11/06 01:19:27 chris Exp $";
#ifdef HAVE_CONFIG_H
#include "configuration.h"
#endif /* HAVE_CONFIG_H */
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/mman.h>
#include "md5.h"
#include "util.h"
/* xwrite FD DATA COUNT
* Write some data, taking account of short writes and signals. */
ssize_t xwrite(int fd, const void *buf, size_t count) {
size_t c = count;
const char *b = (const char*)buf;
while (c > 0) {
int e;
e = write(fd, b, c);
if (e >= 0) {
c -= e;
b += e;
} else if (errno != EINTR) return e;
}
return count;
}
/* daemon:
* Become a daemon. From `The Unix Programming FAQ', Andrew Gierth et al. */
int daemon(int nochdir, int noclose) {
switch (fork()) {
case 0: break;
case -1: return -1;
default: _exit(0); /* exit the original process */
}
if (setsid() < 0) /* shouldn't fail */
return -1;
switch (fork()) {
case 0: break;
case -1: return -1;
default: _exit(0);
}
if (!nochdir) chdir("/");
if (!noclose) {
int i, j = sysconf(_SC_OPEN_MAX); /* getdtablesize()? */
for (i = 0; i < j; ++i) close(i);
open("/dev/null",O_RDWR);
dup(0); dup(0);
}
return 0;
}
#ifndef HAVE_INET_ATON
/* inet_aton:
* Implementation of inet_aton for machines (Solaris [cough]) which do not
* have it. */
int inet_aton(const char *s, struct in_addr *ip) {
in_addr_t i = inet_addr(s);
if (i == ((in_addr_t)-1)) return 0;
memcpy(ip, &i, sizeof(int));
return 1;
}
#endif /* !HAVE_INET_ATON */
/* parse_uid:
* Get a user id from a user name or number. Sets u and returns 1 on success,
* or returns 0 on failure. */
int parse_uid(const char *user, uid_t *u) {
char *v;
long l;
/* Numeric user id? */
l = strtol(user, &v, 10);
if (v && !*v) {
*u = (uid_t)l;
return 1;
} else {
struct passwd *pw = getpwnam(user);
if (pw) {
*u = pw->pw_uid;
return 1;
}
}
return 0;
}
/* xsignal NUMBER HANDLER
* Set a signal with a similar interface to signal(2) using sigaction(2). */
void (*xsignal(int signum, void(*handler)(int)))(int) {
struct sigaction sa = {0}, sa_old;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
if (sigaction(signum, &sa, &sa_old) == -1)
return SIG_ERR;
else
return sa_old.sa_handler;
}
/* parse_gid:
* Get a group id from a group name or number. Sets g and returns 1 on
* success, or returns 0 on failure. */
gid_t parse_gid(const char *group, gid_t *g) {
char *v;
long l;
/* Numeric group id? */
l = strtol(group, &v, 10);
if (v && !*v) {
*g = (gid_t)l;
return 1;
} else {
struct group *grp = getgrnam(group);
if (grp) {
*g = grp->gr_gid;
return 1;
}
}
return 0;
}
/* hex_digest:
* Make a hex version of a digest. */
char *hex_digest(const unsigned char *u) {
static char hex[33] = {0};
const unsigned char *p;
char *q;
for (p = u, q = hex; p < u + 16; ++p, q += 2)
snprintf(q, 3, "%02x", (unsigned int)*p);
return hex;
}
/* unhex_digest:
* Turn a hex representation of a digest into binary data. Returns 1 on
* success or 0 on failure. */
int unhex_digest(const char *from, unsigned char *to) {
const char *p;
unsigned char *q;
for (p = from, q = to; *p && q < to + 16; ++q) {
*q = 0;
if (strchr("0123456789", *p)) *q |= ((unsigned int)*p - '0') << 4;
else if (strchr("abcdef", *p)) *q |= ((unsigned int)*p - 'a' + 10) << 4;
else if (strchr("ABCDEF", *p)) *q |= ((unsigned int)*p - 'A' + 10) << 4;
else return 0;
++p;
if (strchr("0123456789", *p)) *q |= ((unsigned int)*p - '0');
else if (strchr("abcdef", *p)) *q |= ((unsigned int)*p - 'a' + 10);
else if (strchr("ABCDEF", *p)) *q |= ((unsigned int)*p - 'A' + 10);
else return 0;
++p;
}
return 1;
}
#ifndef MTRACE_DEBUGGING
/* xmalloc COUNT
* Malloc, and abort if malloc fails. */
void *xmalloc(size_t n) {
void *v;
v = malloc(n);
if (!v) abort();
return v;
}
/* xcalloc NITEMS COUNT
* As above. */
void *xcalloc(size_t n, size_t m) {
void *v;
v = calloc(n, m);
if (!v) abort();
return v;
}
/* xrealloc PTR COUNT
* As above. */
void *xrealloc(void *w, size_t n) {
void *v;
v = realloc(w, n);
if (n != 0 && !v) abort();
return v;
}
/* xfree PTR
* Free, ignoring a passed NULL value. */
void xfree(void *v) {
if (v) free(v);
}
/* xstrdup:
* Strdup, aborting on failure. */
char *xstrdup(const char *s) {
char *t;
t = xmalloc(strlen(s) + 1);
strcpy(t, s);
return t;
}
#endif /* !MTRACE_DEBUGGING */
/* xstrndup STRING COUNT
* Allocate a new buffer and copy in to it the first COUNT bytes of STRING,
* terminating it with a null. */
char *xstrndup(const char *s, const size_t count) {
char *S;
S = xmalloc(count + 1);
memcpy(S, s, count);
S[count] = 0;
return S;
}
/* md5_digest DATA COUNT MD5
* Save in MD5 the MD5 digest of the first COUNT bytes of DATA. */
void md5_digest(const void *v, const size_t n, unsigned char *md5) {
md5_ctx ctx;
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char*)v, n);
MD5Final(md5, &ctx);
}
/* md5_digest_str DATA COUNT BASE64
* Return a static string containing a printable representation of the MD5 hash
* of the first COUNT bytes of DATA; in hex by default or in base64 if BASE64
* is nonzero. */
char *md5_digest_str(const void *v, const size_t n, const int base64) {
unsigned char md5[16], *p;
static char res[33] = {0};
char *q;
md5_digest(v, n, md5);
if (base64) {
/* Base 64 encoding per RFC2045 as from LDAP. */
const char b64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (p = md5, q = res; p < md5 + 16; p += 3, q += 4) {
char s[5] = "====";
#define P(i) (p + i > md5 + 16 ? *(p + i) : 0)
s[0] = b64[P(0) >> 2];
s[1] = b64[(P(0) & 0x3 << 4) | (P(1) & 0xf0 >> 4)];
if (p + 1 < md5 + 16)
s[2] = b64[(P(1) & 0xf << 2) | (P(2) & 0xc0 >> 4)];
if (p + 2 < md5 + 16)
s[3] = b64[P(2) & 0x3f];
strcat(res, s);
#undef P
}
} else {
/* Conventional hex encoding. */
for (p = md5, q = res; p < md5 + 16; ++p, q += 2)
sprintf(q, "%02x", (unsigned int)*p);
}
return res;
}
/* getmaplength LENGTH
* Return a multiple of the system page size which is equal to or larger than
* LENGTH, to be used as a parameter to mmap(2). */
size_t getmaplength(const size_t len) {
return ((len + PAGESIZE - 1) / PAGESIZE) * PAGESIZE;
}
syntax highlighted by Code2HTML, v. 0.9.1