webpftable/webpftable.c

215 lines
3.8 KiB
C

/*
* CGI to add stuff to a pf table on successful entry of a username and password
* I hope it's secure; must run suid root
* (C)2005-2010, Dan Ponte <amigan@gmail.com>
* 2-clause BSD license
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pwd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <net/pfvar.h>
#ifndef TMPTAB
#define TMPTAB "webtable"
#endif
void add_addr(fd, add)
int fd;
int add;
{
struct pfioc_table pftb;
struct pfr_table ttb;
struct pfr_addr addr;
struct in_addr tad;
int i;
char *raddr;
#define NTABS 20
raddr = getenv("REMOTE_ADDR");
if(raddr == NULL) {
printf("No remote_addr!\n");
exit(-23);
}
bzero(&ttb, sizeof(ttb));
bzero(&pftb, sizeof pftb);
bzero(&addr, sizeof addr);
strncpy(ttb.pfrt_name, TMPTAB, sizeof(ttb.pfrt_name));
pftb.pfrio_table = ttb;
pftb.pfrio_buffer = &addr;
pftb.pfrio_size = 1;
pftb.pfrio_esize = sizeof(struct pfr_addr);
inet_aton(raddr, &tad);
bcopy(&tad, &addr.pfra_ip4addr, 4);
addr.pfra_af = AF_INET;
addr.pfra_net = 32;
if(add) {
i = ioctl(fd, DIOCRADDADDRS, &pftb);
if(i == -1) {
perror("ioctl DIOCRADDADDRS");
exit(-23);
}
} else {
i = ioctl(fd, DIOCRDELADDRS, &pftb);
if(i == -1) {
perror("ioctl DIOCRDELADDRS");
exit(-23);
}
}
}
int check_crendentials(void)
{
char bfr[512];
char *loginname, *pass;
char *tok, *ntok;
size_t len;
char *encpass;
struct passwd *pd;
fgets(bfr, 511, stdin);
tok = strstr(bfr, "login=");
if(tok == NULL) {
printf("no login=\n");
return 0;
}
tok += strlen("login=");
ntok = strchr(tok, '&');
if(ntok == NULL) {
printf("no ampersand\n");
return 0;
}
len = (size_t)(ntok - tok) + 1;
loginname = malloc(len);
if(loginname == NULL) {
printf("malloc error for loginname\n");
return 0;
}
bzero(loginname, len);
strncpy(loginname, tok, len - 1);
tok = strstr(bfr, "passwd=");
if(tok == NULL) {
printf("no passwd=\n");
return 0;
}
tok += strlen("passwd=");
ntok = strchr(tok, '&');
if(ntok == NULL)
if((ntok = strchr(tok, '\0')) == NULL) {
printf("dbl no amp\n");
return 0;
}
len = (size_t)(ntok - tok) + 1;
pass = malloc(len);
if(pass == NULL) {
printf("malloc error for passwd\n");
return 0;
}
bzero(pass, len);
strncpy(pass, tok, len - 1);
errno = 0;
pd = getpwnam(loginname);
if(pd == NULL) {
if(errno != 0) {
printf("getpwnam error: %s\n", strerror(errno));
}
return 0;
}
encpass = crypt(pass, pd->pw_passwd);
if(encpass == NULL) {
printf("null encpass\n");
return 0;
}
free(loginname);
free(pass);
if(strcmp(encpass, pd->pw_passwd) == 0)
return 1;
else
return 0;
}
int main(argc, argv)
int argc;
char **argv;
{
char *req_method;
int pffd;
if(getenv("GATEWAY_INTERFACE") == NULL) {
fprintf(stderr, "Must be run as a CGI! Aborting.\n");
exit(-1);
}
printf("Content-Type: text/html\n\n<!DOCTYPE html\n"
"PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999.xhtml\">\n"
"<head><title>webpftable</title></head>\n<body>\n"
);
if((req_method = getenv("REQUEST_METHOD")) == NULL) {
fprintf(stderr, "CGI!\n");
exit(-2);
}
if(strcmp(req_method, "POST") != 0) {
printf("Must be POST!\n");
exit(-3);
}
if((pffd = open("/dev/pf", O_RDWR)) < 0 ) {
perror("open pf");
exit(-4);
}
if(check_crendentials()) {
add_addr(pffd, 1);
printf("<p>Added! Have fun!</p>\n");
}else {
add_addr(pffd, 0);
printf("<p>Incorrect login and/or password. Try again.</p>\n");
printf("<p>Your IP has been removed from table if it was there.</p>\n");
}
close(pffd);
printf("</body></html>\n");
return 0;
}