1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "defines.h"
void run_age_cmd(const char* remoteip)
{
pid_t pid = fork();
if(pid == 0) {
const char* devnul = "/dev/null";
close(0);
close(1);
close(2);
open(devnul, O_RDONLY); /* fd 0 */
open(devnul, O_WRONLY); /* fd 1 */
open(devnul, O_WRONLY); /* fd 2 */
execl(AGE_CMD, AGE_CMD, remoteip, 0);
exit(111);
} else if(pid < 0) {
perror("fork");
exit(111);
}
}
void authenticated(const char* tcpremoteip)
{
run_age_cmd(tcpremoteip);
/* Since this program will be either setuid or setgid,
revoke our priviledges now. */
setgid(getgid());
setuid(getuid());
}
size_t writestr(int fd, const char* msg)
{
return write(fd, msg, strlen(msg));
}
const char* validate(const char* str)
{
/* Security by obscurity -- do certain simple checks on the remote
IP string and require that both stdin and stdout are sockets.
Also require that UID and GID are non-zero. */
const char* ptr;
/* Skip over a IPv6 address prefix inserted by couriertcpd */
if(!strncmp(str, "::ffff:", 7))
str += 7;
/* Ensure that the IP string contains only digits and periods. */
for(ptr = str; *ptr != 0; ptr++) {
char ch = *ptr;
if(ch != '.' && !isdigit(ch))
return 0;
}
return str;
}
enum { imap, pop3 } authmode;
int main(int argc, char* argv[])
{
struct stat statbuf;
const char* tcpremoteip = getenv("TCPREMOTEIP");
if(!tcpremoteip || !(tcpremoteip = validate(tcpremoteip))) {
writestr(2,
"Error: relay-ctrl-allow must be run from tcp-env or tcpserver");
return 111;
}
if(getuid() == 0 || getgid() == 0) {
writestr(2,
"Error: relay-ctrl-allow cannot be run as root");
return 111;
}
/* Check command-line arguments */
if(argc < 2) {
writestr(2, "Error: too few command-line arguments to relay-ctrl-allow");
writestr(2, "usage: relay-ctrl-allow program args...");
return 111;
}
/* Auto-detect the type of program running relay-ctrl-allow */
if(getenv("AUTHUSER") && getenv("AUTHARGV0") && fstat(3, &statbuf) != -1)
authmode = imap;
else
authmode = pop3;
switch(authmode) {
case imap:
if(getenv("AUTHENTICATED"))
authenticated(tcpremoteip);
break;
case pop3:
authenticated(tcpremoteip);
break;
}
execvp(argv[1], argv+1);
return 111;
}
|