From
http://svn.blinkenlights.nl/viewvc.cgi/vhostlog/trunk/
Makefile
CC = gcc
DEBUG = -Wall -g
all: vhostlog
vhostlog.o: vhostlog.c
$(CC) ${DEBUG} -O -c vhostlog.c
vhostlog: vhostlog.o
$(CC) ${DEBUG} -o vhostlog vhostlog.o
clean:
rm -f vhostlog *.o core *.core
vhostlog.c
/*
vhostlog.c
This program is supposed to run from apache via a pipe
in a CustomLog statement, or as a daemon under daemontools/
inittab/etc in fifo mode.
Configure it as follows:
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" " vhostlog
#Pipe Version
CustomLog "|/usr/local/bin/vhostlog www /var/log/apache" vhostlog
#Fifo Version
CustomLog "/var/path/to/vhostlog/fifo" vhostlog
The first argument is the user to switch to (www), the second is the
directory in which logfiles are stored ( /var/log/apache ).
The owner of the log directory *has* to be the same as the log user.
Written by Johan Mulder <johan@localhost.nl> at november 28th 2001.
Modified by Sten Spans <sten@blinkenlights.nl> at $Date$.
*/
const char cvsid[] = "$Id$";
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#define UMASK S_IRWXG | S_IRWXO
#define NOLOGGING "/var/service/vhostlog/root/down"
#define MAXLINESIZE 16384
#define VHOSTCHARS "abcdefghijklmnopqrstuvwxyz0123456789.-_"
/* #define DEBUG */
char hostname[MAXHOSTNAMELEN+1];
static int logline(char *, const char *, unsigned int *);
int main(int argc, char **argv)
{
char line[MAXLINESIZE];
char *logdir;
char *user;
char *fifo_path = NULL;
struct passwd *pwd;
unsigned int failed = 0;
unsigned int longline = 0;
struct stat s;
FILE *input = stdin;
/* Get the config */
#ifdef DEBUG
fprintf(stderr, "Getting the config\n");
#endif
if (argc < 3 || argc > 4)
{
fprintf(stderr, "Usage %s user logdir [fifo]\n", argv[0]);
return 1;
}
user = argv[1];
logdir = argv[2];
if(argc == 4)
fifo_path = argv[3];
/* Check if the user to setuid to actually exists */
#ifdef DEBUG
fprintf(stderr, "Checking if the user exists\n");
#endif
if ((pwd = getpwnam(user)) == NULL)
{
fprintf(stderr, "User %s does not exist\n", user);
return 1;
}
/* Check if the logdir exists */
#ifdef DEBUG
fprintf(stderr, "Checking if the logdir exists\n");
#endif
if (stat(logdir, &s) == -1 || chdir(logdir) == -1)
{
fprintf(stderr, "Unable to change dir to %s: %s\n",
logdir, strerror(errno));
return 1;
}
/* Check the ownership of that directory */
#ifdef DEBUG
fprintf(stderr, "Checking logdir ownership\n");
#endif
if (s.st_uid != pwd->pw_uid)
{
fprintf(stderr, "Bad owner on directory %s (should be owner %s).\n",
logdir, user);
return 1;
}
/* Change the uid */
#ifdef DEBUG
fprintf(stderr, "Changing uid/gid\n");
#endif
if(setgid(pwd->pw_gid) == -1){
fprintf(stderr, "Unable to setgid: %s\n", strerror(errno));
return 1;
}
if(setgroups(0, NULL) == -1){
fprintf(stderr, "Unable to setgroups: %s\n", strerror(errno));
return 1;
}
if(setuid(pwd->pw_uid) == -1){
fprintf(stderr, "Unable to setuid: %s\n", strerror(errno));
return 1;
}
/* Get hostname */
if(gethostname(hostname, sizeof(hostname)) == -1){
fprintf(stderr, "Unable to get hostname: %s\n", strerror(errno));
return 1;
}
/* Change umask */
umask(UMASK);
/* Check/Create Fifo */
if(fifo_path != NULL) {
#ifdef DEBUG
fprintf(stderr, "Checking/Creating the fifo: %s\n", fifo_path);
#endif
if (stat(fifo_path, &s) == -1) {
if(errno != ENOENT) {
fprintf(stderr, "Unable to stat fifo %s: %s\n",
fifo_path, strerror(errno));
return 1;
} else if (mkfifo(fifo_path, S_IRWXU) == -1) {
fprintf(stderr, "Unable to create fifo %s: %s\n",
fifo_path, strerror(errno));
return 1;
}
} else if (!S_ISFIFO(s.st_mode)) {
fprintf(stderr, "Expected fifo at %s, got something else\n",
fifo_path);
return 1;
}
if ((input = fopen(fifo_path, "r+")) == NULL) {
fprintf(stderr, "Failed opening fifo %s: %s\n",
fifo_path, strerror(errno));
return 1;
}
}
/* Process the logging */
#ifdef DEBUG
fprintf(stderr, "Process the logging\n");
#endif
while (feof(input) == 0) {
if ((fgets(line, MAXLINESIZE, input)) != NULL)
if (access(NOLOGGING, F_OK) == -1)
if (logline(line, logdir, &longline) == 1)
fprintf(stderr, " %u logging failures\n", ++failed);
}
return 0;
}
/* This function writes a logline in clf to a logfile */
int logline(char *line, const char *logdir, unsigned int *longline)
{
char *outline, *vhost;
char logfile[PATH_MAX+1];
FILE *outfile;
outline = vhost = NULL;
/* initial checks */
#ifdef DEBUG
fprintf(stderr, "Initial Checks\n");
#endif
if (!line || (strlen(line) == 0)) {
fprintf(stderr, "Incorrect logline: too short,");
return 1;
} else if((strchr(line, '\n') == NULL) && *longline == 0){
fprintf(stderr, "Incorrect logline: too long,");
*longline = 1;
return 1;
} else if((strchr(line, '\n') == NULL) && *longline == 1){
return 0;
} else if((strchr(line, '\n') != NULL) && *longline == 1){
*longline = 0;
return 0;
};
if(!logdir || (strlen(logdir) == 0)) {
fprintf(stderr, "Incorrect logdir: too short,");
return 1;
}
/* Determine the vhost and logfile location */
#ifdef DEBUG
fprintf(stderr, "Getting vhost from logline\n");
#endif
vhost = line;
outline = index(line, ' ');
if(outline == NULL) {
fprintf(stderr, "Incorrect logline: no vhost,");
return 1;
}
*outline = '\0';
outline++;
/* If the vhost is ".." or "." then reject it */
if (strcmp(vhost, "..") == 0 || strcmp(vhost, ".") == 0) {
fprintf(stderr,"Incorrect vhost: invalid chars,");
return 1;
}
/* If the "vhost" part contains invalid chars
then log the entire line to "hostname" */
if (strspn(vhost, VHOSTCHARS) != strlen(vhost)) {
outline[-1] = ' ';
outline = line;
vhost = hostname;
}
if (strlen(vhost) < 1 || strlen(outline) < 1) {
fprintf(stderr,"Incorrect vhost/line: too short,");
return 1;
}
#ifdef DEBUG
fprintf(stderr, "Got vhost: %s\n", vhost);
#endif
if ((strlen(logdir) + strlen(vhost)) > PATH_MAX) {
fprintf(stderr, "Incorrect logdir/vhost: too long,");
return 1;
}
if (snprintf(logfile, PATH_MAX+1, "%s/%s", logdir, vhost) < 0) {
fprintf(stderr, "Error building logfile string,");
return 1;
}
#ifdef DEBUG
fprintf(stderr, "Got logfile: %s\n", logfile);
#endif
/* Open logfile, and write the output */
#ifdef DEBUG
fprintf(stderr, "Writing output to logfile\n");
#endif
if ((outfile = fopen(logfile, "a")) == NULL) {
fprintf(stderr, "Failed opening logfile %s: %s,",
logfile, strerror(errno));
return 1;
}
if (fputs(outline, outfile) < 0) {
fprintf(stderr, "Failed writing to logfile %s,", logfile);
if (fclose(outfile) == EOF) {
fprintf(stderr, "Failed closing logfile %s: %s,",
logfile, strerror(errno));
return 1;
};
};
if (fclose(outfile) == EOF) {
fprintf(stderr, "Failed closing logfile %s: %s,",
logfile, strerror(errno));
return 1;
};
return 0;
}
