xref: /freebsd/contrib/ntp/ntpd/ntp_signd.c (revision 009e81b16465ea457c0e63fd49fe77f47cc27a5a)
12b15cb3dSCy Schubert /* Copyright 2008, Red Hat, Inc.
22b15cb3dSCy Schubert    Copyright 2008, Andrew Tridgell.
32b15cb3dSCy Schubert    Licenced under the same terms as NTP itself.
42b15cb3dSCy Schubert  */
52b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
62b15cb3dSCy Schubert #include <config.h>
72b15cb3dSCy Schubert #endif
82b15cb3dSCy Schubert 
92b15cb3dSCy Schubert #ifdef HAVE_NTP_SIGND
102b15cb3dSCy Schubert 
112b15cb3dSCy Schubert #include "ntpd.h"
122b15cb3dSCy Schubert #include "ntp_io.h"
132b15cb3dSCy Schubert #include "ntp_stdlib.h"
142b15cb3dSCy Schubert #include "ntp_unixtime.h"
152b15cb3dSCy Schubert #include "ntp_control.h"
162b15cb3dSCy Schubert #include "ntp_string.h"
172b15cb3dSCy Schubert 
182b15cb3dSCy Schubert #include <stdio.h>
192b15cb3dSCy Schubert #include <stddef.h>
202b15cb3dSCy Schubert #ifdef HAVE_LIBSCF_H
212b15cb3dSCy Schubert #include <libscf.h>
222b15cb3dSCy Schubert #include <unistd.h>
232b15cb3dSCy Schubert #endif /* HAVE_LIBSCF_H */
242b15cb3dSCy Schubert 
252b15cb3dSCy Schubert #include <sys/un.h>
262b15cb3dSCy Schubert 
272b15cb3dSCy Schubert /* socket routines by tridge - from junkcode.samba.org */
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert /*
302b15cb3dSCy Schubert   connect to a unix domain socket
312b15cb3dSCy Schubert */
322b15cb3dSCy Schubert static int
ux_socket_connect(const char * name)332b15cb3dSCy Schubert ux_socket_connect(const char *name)
342b15cb3dSCy Schubert {
352b15cb3dSCy Schubert 	int fd;
362b15cb3dSCy Schubert 	struct sockaddr_un addr;
372b15cb3dSCy Schubert 	if (!name) {
382b15cb3dSCy Schubert 		return -1;
392b15cb3dSCy Schubert 	}
402b15cb3dSCy Schubert 
412b15cb3dSCy Schubert 	ZERO(addr);
422b15cb3dSCy Schubert 	addr.sun_family = AF_UNIX;
432b15cb3dSCy Schubert 	strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
462b15cb3dSCy Schubert 	if (fd == -1) {
472b15cb3dSCy Schubert 		return -1;
482b15cb3dSCy Schubert 	}
492b15cb3dSCy Schubert 
502b15cb3dSCy Schubert 	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
512b15cb3dSCy Schubert 		close(fd);
522b15cb3dSCy Schubert 		return -1;
532b15cb3dSCy Schubert 	}
542b15cb3dSCy Schubert 
552b15cb3dSCy Schubert 	return fd;
562b15cb3dSCy Schubert }
572b15cb3dSCy Schubert 
582b15cb3dSCy Schubert 
592b15cb3dSCy Schubert /*
602b15cb3dSCy Schubert   keep writing until its all sent
612b15cb3dSCy Schubert */
622b15cb3dSCy Schubert static int
write_all(int fd,const void * buf,size_t len)632b15cb3dSCy Schubert write_all(int fd, const void *buf, size_t len)
642b15cb3dSCy Schubert {
652b15cb3dSCy Schubert 	size_t total = 0;
662b15cb3dSCy Schubert 	while (len) {
672b15cb3dSCy Schubert 		int n = write(fd, buf, len);
682b15cb3dSCy Schubert 		if (n <= 0) return total;
69*3311ff84SXin LI 		buf = n + (const char *)buf;
702b15cb3dSCy Schubert 		len -= n;
712b15cb3dSCy Schubert 		total += n;
722b15cb3dSCy Schubert 	}
732b15cb3dSCy Schubert 	return total;
742b15cb3dSCy Schubert }
752b15cb3dSCy Schubert 
762b15cb3dSCy Schubert /*
772b15cb3dSCy Schubert   keep reading until its all read
782b15cb3dSCy Schubert */
792b15cb3dSCy Schubert static int
read_all(int fd,void * buf,size_t len)802b15cb3dSCy Schubert read_all(int fd, void *buf, size_t len)
812b15cb3dSCy Schubert {
822b15cb3dSCy Schubert 	size_t total = 0;
832b15cb3dSCy Schubert 	while (len) {
842b15cb3dSCy Schubert 		int n = read(fd, buf, len);
852b15cb3dSCy Schubert 		if (n <= 0) return total;
862b15cb3dSCy Schubert 		buf = n + (char *)buf;
872b15cb3dSCy Schubert 		len -= n;
882b15cb3dSCy Schubert 		total += n;
892b15cb3dSCy Schubert 	}
902b15cb3dSCy Schubert 	return total;
912b15cb3dSCy Schubert }
922b15cb3dSCy Schubert 
932b15cb3dSCy Schubert /*
942b15cb3dSCy Schubert   send a packet in length prefix format
952b15cb3dSCy Schubert */
962b15cb3dSCy Schubert static int
send_packet(int fd,const char * buf,uint32_t len)972b15cb3dSCy Schubert send_packet(int fd, const char *buf, uint32_t len)
982b15cb3dSCy Schubert {
992b15cb3dSCy Schubert 	uint32_t net_len = htonl(len);
1002b15cb3dSCy Schubert 	if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1;
1012b15cb3dSCy Schubert 	if (write_all(fd, buf, len) != len) return -1;
1022b15cb3dSCy Schubert 	return 0;
1032b15cb3dSCy Schubert }
1042b15cb3dSCy Schubert 
1052b15cb3dSCy Schubert /*
1062b15cb3dSCy Schubert   receive a packet in length prefix format
1072b15cb3dSCy Schubert */
1082b15cb3dSCy Schubert static int
recv_packet(int fd,char ** buf,uint32_t * len)1092b15cb3dSCy Schubert recv_packet(int fd, char **buf, uint32_t *len)
1102b15cb3dSCy Schubert {
1112b15cb3dSCy Schubert 	if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
1122b15cb3dSCy Schubert 	*len = ntohl(*len);
113*3311ff84SXin LI 	*buf = emalloc(*len);
1142b15cb3dSCy Schubert 	if (read_all(fd, *buf, *len) != *len) {
1152b15cb3dSCy Schubert 		free(*buf);
116*3311ff84SXin LI 		*buf = NULL;
1172b15cb3dSCy Schubert 		return -1;
1182b15cb3dSCy Schubert 	}
1192b15cb3dSCy Schubert 	return 0;
1202b15cb3dSCy Schubert }
1212b15cb3dSCy Schubert 
1222b15cb3dSCy Schubert void
send_via_ntp_signd(struct recvbuf * rbufp,int xmode,keyid_t xkeyid,int flags,struct pkt * xpkt)1232b15cb3dSCy Schubert send_via_ntp_signd(
1242b15cb3dSCy Schubert 	struct recvbuf *rbufp,	/* receive packet pointer */
1252b15cb3dSCy Schubert 	int	xmode,
1262b15cb3dSCy Schubert 	keyid_t	xkeyid,
1272b15cb3dSCy Schubert 	int flags,
1282b15cb3dSCy Schubert 	struct pkt  *xpkt
1292b15cb3dSCy Schubert 	)
1302b15cb3dSCy Schubert {
1312b15cb3dSCy Schubert 
1322b15cb3dSCy Schubert 	/* We are here because it was detected that the client
1332b15cb3dSCy Schubert 	 * sent an all-zero signature, and we therefore know
1342b15cb3dSCy Schubert 	 * it's windows trying to talk to an AD server
1352b15cb3dSCy Schubert 	 *
1362b15cb3dSCy Schubert 	 * Because we don't want to dive into Samba's secrets
1372b15cb3dSCy Schubert 	 * database just to find the long-term kerberos key
1382b15cb3dSCy Schubert 	 * that is re-used as the NTP key, we instead hand the
1392b15cb3dSCy Schubert 	 * packet over to Samba to sign, and return to us.
1402b15cb3dSCy Schubert 	 *
1412b15cb3dSCy Schubert 	 * The signing method Samba will use is described by
1422b15cb3dSCy Schubert 	 * Microsoft in MS-SNTP, found here:
1432b15cb3dSCy Schubert 	 * http://msdn.microsoft.com/en-us/library/cc212930.aspx
1442b15cb3dSCy Schubert 	 */
1452b15cb3dSCy Schubert 
1462b15cb3dSCy Schubert 	int fd, sendlen;
1472b15cb3dSCy Schubert 	struct samba_key_in {
1482b15cb3dSCy Schubert 		uint32_t version;
1492b15cb3dSCy Schubert 		uint32_t op;
1502b15cb3dSCy Schubert 		uint32_t packet_id;
1512b15cb3dSCy Schubert 		uint32_t key_id_le;
1522b15cb3dSCy Schubert 		struct pkt pkt;
1532b15cb3dSCy Schubert 	} samba_pkt;
1542b15cb3dSCy Schubert 
1552b15cb3dSCy Schubert 	struct samba_key_out {
1562b15cb3dSCy Schubert 		uint32_t version;
1572b15cb3dSCy Schubert 		uint32_t op;
1582b15cb3dSCy Schubert 		uint32_t packet_id;
1592b15cb3dSCy Schubert 		struct pkt pkt;
1602b15cb3dSCy Schubert 	} samba_reply;
1612b15cb3dSCy Schubert 
1622b15cb3dSCy Schubert 	char full_socket[256];
1632b15cb3dSCy Schubert 
1642b15cb3dSCy Schubert 	char *reply = NULL;
1652b15cb3dSCy Schubert 	uint32_t reply_len;
1662b15cb3dSCy Schubert 
1672b15cb3dSCy Schubert 	ZERO(samba_pkt);
1682b15cb3dSCy Schubert 	samba_pkt.op = 0; /* Sign message */
1692b15cb3dSCy Schubert 	/* This will be echoed into the reply - a different
1702b15cb3dSCy Schubert 	 * impelementation might want multiple packets
1712b15cb3dSCy Schubert 	 * awaiting signing */
1722b15cb3dSCy Schubert 
1732b15cb3dSCy Schubert 	samba_pkt.packet_id = 1;
1742b15cb3dSCy Schubert 
1752b15cb3dSCy Schubert 	/* Swap the byte order back - it's actually little
1762b15cb3dSCy Schubert 	 * endian on the wire, but it was read above as
1772b15cb3dSCy Schubert 	 * network byte order */
1782b15cb3dSCy Schubert 	samba_pkt.key_id_le = htonl(xkeyid);
1792b15cb3dSCy Schubert 	samba_pkt.pkt = *xpkt;
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert 	snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
1822b15cb3dSCy Schubert 
1832b15cb3dSCy Schubert 	fd = ux_socket_connect(full_socket);
1842b15cb3dSCy Schubert 	/* Only continue with this if we can talk to Samba */
1852b15cb3dSCy Schubert 	if (fd != -1) {
1862b15cb3dSCy Schubert 		/* Send old packet to Samba, expect response */
1872b15cb3dSCy Schubert 		/* Packet to Samba is quite simple:
1882b15cb3dSCy Schubert 		   All values BIG endian except key ID as noted
1892b15cb3dSCy Schubert 		   [packet size as BE] - 4 bytes
1902b15cb3dSCy Schubert 		   [protocol version (0)] - 4 bytes
1912b15cb3dSCy Schubert 		   [packet ID] - 4 bytes
1922b15cb3dSCy Schubert 		   [operation (sign message=0)] - 4 bytes
1932b15cb3dSCy Schubert 		   [key id] - LITTLE endian (as on wire) - 4 bytes
1942b15cb3dSCy Schubert 		   [message to sign] - as marshalled, without signature
1952b15cb3dSCy Schubert 		*/
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert 		if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
1982b15cb3dSCy Schubert 			/* Huh?  could not talk to Samba... */
1992b15cb3dSCy Schubert 			close(fd);
2002b15cb3dSCy Schubert 			return;
2012b15cb3dSCy Schubert 		}
2022b15cb3dSCy Schubert 
2032b15cb3dSCy Schubert 		if (recv_packet(fd, &reply, &reply_len) != 0) {
2042b15cb3dSCy Schubert 			if (reply) {
2052b15cb3dSCy Schubert 				free(reply);
2062b15cb3dSCy Schubert 			}
2072b15cb3dSCy Schubert 			close(fd);
2082b15cb3dSCy Schubert 			return;
2092b15cb3dSCy Schubert 		}
2102b15cb3dSCy Schubert 		/* Return packet is also simple:
2112b15cb3dSCy Schubert 		   [packet size] - network byte order - 4 bytes
2122b15cb3dSCy Schubert 		   [protocol version (0)] network byte order - - 4 bytes
2132b15cb3dSCy Schubert 		   [operation (signed success=3, failure=4)] network byte order - - 4 byte
2142b15cb3dSCy Schubert 		   (optional) [signed message] - as provided before, with signature appended
2152b15cb3dSCy Schubert 		*/
2162b15cb3dSCy Schubert 
2172b15cb3dSCy Schubert 		if (reply_len <= sizeof(samba_reply)) {
2182b15cb3dSCy Schubert 			memcpy(&samba_reply, reply, reply_len);
2192b15cb3dSCy Schubert 			if (ntohl(samba_reply.op) == 3 && reply_len >  offsetof(struct samba_key_out, pkt)) {
2202b15cb3dSCy Schubert 				sendlen = reply_len - offsetof(struct samba_key_out, pkt);
2212b15cb3dSCy Schubert 				xpkt = &samba_reply.pkt;
2222b15cb3dSCy Schubert 				sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
2232b15cb3dSCy Schubert #ifdef DEBUG
2242b15cb3dSCy Schubert 				if (debug)
2252b15cb3dSCy Schubert 					printf(
2262b15cb3dSCy Schubert 						"transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
2272b15cb3dSCy Schubert 						current_time, ntoa(&rbufp->dstadr->sin),
2282b15cb3dSCy Schubert 						ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
2292b15cb3dSCy Schubert #endif
2302b15cb3dSCy Schubert 			}
2312b15cb3dSCy Schubert 		}
2322b15cb3dSCy Schubert 
2332b15cb3dSCy Schubert 		if (reply) {
2342b15cb3dSCy Schubert 			free(reply);
2352b15cb3dSCy Schubert 		}
2362b15cb3dSCy Schubert 		close(fd);
2372b15cb3dSCy Schubert 
2382b15cb3dSCy Schubert 	}
2392b15cb3dSCy Schubert }
2402b15cb3dSCy Schubert #endif
241