Skip to content

Instantly share code, notes, and snippets.

@jpmens

jpmens/tserv.c

Created Dec 22, 2020
Embed
What would you like to do?
authentication server for named external grant (Unix domain socket)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
/*
* tserv.c (C)2020 by Jan-Piet Mens <jp@mens.de>
* External grant authenticator for BIND's named. This program
* creates a Unix domain socket and awaits a packet from
* named(8) asking whether to grant or deny a particular
* update. See https://jpmens.net/2020/12/20/bind-named-grants-using-external-authenticator/
*/
#define socket_path "/tmp/auth.sock"
#define err(s) perror((s)), exit(2)
void respond(int socket, int response)
{
int n;
response = htonl(response);
if ((n = write(socket, &response, sizeof(response))) != sizeof(response)) {
perror("short write");
}
}
void serve(int s)
{
unsigned char buf[1024], *bp;
int nbytes, proto, plen, permit;
char *signer = NULL, *name = NULL, *addr = NULL,
*rtype = NULL, *key = NULL;
/*
* Protocol version number (4 bytes, network byte order, currently 1)
* Request length (4 bytes, network byte order)
* Signer (null-terminated string)
* Name (null-terminated string)
* TCP source address (null-terminated string)
* Rdata type (null-terminated string)
* Key (null-terminated string)
* TKEY token length (4 bytes, network byte order)
* TKEY token (remainder of packet)
*/
nbytes = read(s, bp = buf, sizeof(buf));
proto = ntohl(*(long *)bp);
bp += 4;
if (proto != 1 || nbytes < 17) {
respond(s, 2);
return;
}
plen = ntohl(*(long *)bp);
bp += 4;
signer = (char *)bp;
bp += strlen(signer) + 1;
name = (char *)bp;
bp += strlen(name) + 1;
addr = (char *)bp;
bp += strlen(addr) + 1;
rtype = (char *)bp;
bp += strlen(rtype) + 1;
key = (char *)bp;
bp += strlen(key) + 1;
/* TKEY len and TKEY follow here, but I'm uninsterested */
/* Example output:
*
* Request len=76
* signer=acme,
* name=www.example.net.certs.example,
* addr=127.0.0.2,
* rtype=TXT,
* key=acme/163/59864
*/
printf("Request len=%d signer=%s, name=%s, addr=%s, rtype=%s, key=%s\n",
plen, signer, name, addr, rtype, key);
/* Set permit = {0|1} to deny or permit respectively */
permit = 1;
respond(s, permit);
}
int main(int argc, char **argv)
{
int s, ns, addrlen;
struct sockaddr_un addr;
if (access(socket_path, F_OK) == 0) {
if (unlink(socket_path) == -1) {
perror(socket_path);
exit(2);
}
}
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
err("socket");
}
memset((char *)&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, strlen(socket_path));
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
err("bind");
}
if (listen(s, 5) < 0) {
err("listen");
}
while (1) {
addrlen = sizeof(addr);
if ((ns = accept(s, (struct sockaddr *)&addr, (socklen_t *)&addrlen)) == -1)
err("accept");
serve(ns);
close(ns);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment