xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_signd.c (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1*cdfa2a7eSchristos /*	$NetBSD: ntp_signd.c,v 1.5 2020/05/25 20:47:25 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /* Copyright 2008, Red Hat, Inc.
4abb0f93cSkardel    Copyright 2008, Andrew Tridgell.
5abb0f93cSkardel    Licenced under the same terms as NTP itself.
6abb0f93cSkardel  */
7abb0f93cSkardel #ifdef HAVE_CONFIG_H
8abb0f93cSkardel #include <config.h>
9abb0f93cSkardel #endif
10abb0f93cSkardel 
11abb0f93cSkardel #ifdef HAVE_NTP_SIGND
12abb0f93cSkardel 
13abb0f93cSkardel #include "ntpd.h"
14abb0f93cSkardel #include "ntp_io.h"
15abb0f93cSkardel #include "ntp_stdlib.h"
16abb0f93cSkardel #include "ntp_unixtime.h"
17abb0f93cSkardel #include "ntp_control.h"
18abb0f93cSkardel #include "ntp_string.h"
19abb0f93cSkardel 
20abb0f93cSkardel #include <stdio.h>
21abb0f93cSkardel #include <stddef.h>
22abb0f93cSkardel #ifdef HAVE_LIBSCF_H
23abb0f93cSkardel #include <libscf.h>
24abb0f93cSkardel #include <unistd.h>
25abb0f93cSkardel #endif /* HAVE_LIBSCF_H */
26abb0f93cSkardel 
27abb0f93cSkardel #include <sys/un.h>
28abb0f93cSkardel 
29abb0f93cSkardel /* socket routines by tridge - from junkcode.samba.org */
30abb0f93cSkardel 
31abb0f93cSkardel /*
32abb0f93cSkardel   connect to a unix domain socket
33abb0f93cSkardel */
34abb0f93cSkardel static int
ux_socket_connect(const char * name)35abb0f93cSkardel ux_socket_connect(const char *name)
36abb0f93cSkardel {
37abb0f93cSkardel 	int fd;
38abb0f93cSkardel 	struct sockaddr_un addr;
39abb0f93cSkardel 	if (!name) {
40abb0f93cSkardel 		return -1;
41abb0f93cSkardel 	}
42abb0f93cSkardel 
438585484eSchristos 	ZERO(addr);
44abb0f93cSkardel 	addr.sun_family = AF_UNIX;
458585484eSchristos 	strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
46abb0f93cSkardel 
47abb0f93cSkardel 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
48abb0f93cSkardel 	if (fd == -1) {
49abb0f93cSkardel 		return -1;
50abb0f93cSkardel 	}
51abb0f93cSkardel 
52abb0f93cSkardel 	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
53abb0f93cSkardel 		close(fd);
54abb0f93cSkardel 		return -1;
55abb0f93cSkardel 	}
56abb0f93cSkardel 
57abb0f93cSkardel 	return fd;
58abb0f93cSkardel }
59abb0f93cSkardel 
60abb0f93cSkardel 
61abb0f93cSkardel /*
62abb0f93cSkardel   keep writing until its all sent
63abb0f93cSkardel */
64abb0f93cSkardel static int
write_all(int fd,const void * buf,size_t len)65abb0f93cSkardel write_all(int fd, const void *buf, size_t len)
66abb0f93cSkardel {
67abb0f93cSkardel 	size_t total = 0;
68abb0f93cSkardel 	while (len) {
69abb0f93cSkardel 		int n = write(fd, buf, len);
70abb0f93cSkardel 		if (n <= 0) return total;
718b8da087Schristos 		buf = n + (const char *)buf;
72abb0f93cSkardel 		len -= n;
73abb0f93cSkardel 		total += n;
74abb0f93cSkardel 	}
75abb0f93cSkardel 	return total;
76abb0f93cSkardel }
77abb0f93cSkardel 
78abb0f93cSkardel /*
79abb0f93cSkardel   keep reading until its all read
80abb0f93cSkardel */
81abb0f93cSkardel static int
read_all(int fd,void * buf,size_t len)82abb0f93cSkardel read_all(int fd, void *buf, size_t len)
83abb0f93cSkardel {
84abb0f93cSkardel 	size_t total = 0;
85abb0f93cSkardel 	while (len) {
86abb0f93cSkardel 		int n = read(fd, buf, len);
87abb0f93cSkardel 		if (n <= 0) return total;
88abb0f93cSkardel 		buf = n + (char *)buf;
89abb0f93cSkardel 		len -= n;
90abb0f93cSkardel 		total += n;
91abb0f93cSkardel 	}
92abb0f93cSkardel 	return total;
93abb0f93cSkardel }
94abb0f93cSkardel 
95abb0f93cSkardel /*
96abb0f93cSkardel   send a packet in length prefix format
97abb0f93cSkardel */
98abb0f93cSkardel static int
send_packet(int fd,const char * buf,uint32_t len)99abb0f93cSkardel send_packet(int fd, const char *buf, uint32_t len)
100abb0f93cSkardel {
101abb0f93cSkardel 	uint32_t net_len = htonl(len);
102abb0f93cSkardel 	if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1;
103abb0f93cSkardel 	if (write_all(fd, buf, len) != len) return -1;
104abb0f93cSkardel 	return 0;
105abb0f93cSkardel }
106abb0f93cSkardel 
107abb0f93cSkardel /*
108abb0f93cSkardel   receive a packet in length prefix format
109abb0f93cSkardel */
110abb0f93cSkardel static int
recv_packet(int fd,char ** buf,uint32_t * len)111abb0f93cSkardel recv_packet(int fd, char **buf, uint32_t *len)
112abb0f93cSkardel {
113abb0f93cSkardel 	if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
114abb0f93cSkardel 	*len = ntohl(*len);
1158b8da087Schristos 	*buf = emalloc(*len);
116abb0f93cSkardel 	if (read_all(fd, *buf, *len) != *len) {
117abb0f93cSkardel 		free(*buf);
1188b8da087Schristos 		*buf = NULL;
119abb0f93cSkardel 		return -1;
120abb0f93cSkardel 	}
121abb0f93cSkardel 	return 0;
122abb0f93cSkardel }
123abb0f93cSkardel 
124abb0f93cSkardel void
send_via_ntp_signd(struct recvbuf * rbufp,int xmode,keyid_t xkeyid,int flags,struct pkt * xpkt)125abb0f93cSkardel send_via_ntp_signd(
126abb0f93cSkardel 	struct recvbuf *rbufp,	/* receive packet pointer */
127abb0f93cSkardel 	int	xmode,
128abb0f93cSkardel 	keyid_t	xkeyid,
129abb0f93cSkardel 	int flags,
130abb0f93cSkardel 	struct pkt  *xpkt
131abb0f93cSkardel 	)
132abb0f93cSkardel {
133abb0f93cSkardel 
134abb0f93cSkardel 	/* We are here because it was detected that the client
135abb0f93cSkardel 	 * sent an all-zero signature, and we therefore know
136abb0f93cSkardel 	 * it's windows trying to talk to an AD server
137abb0f93cSkardel 	 *
138abb0f93cSkardel 	 * Because we don't want to dive into Samba's secrets
139abb0f93cSkardel 	 * database just to find the long-term kerberos key
140abb0f93cSkardel 	 * that is re-used as the NTP key, we instead hand the
141abb0f93cSkardel 	 * packet over to Samba to sign, and return to us.
142abb0f93cSkardel 	 *
143abb0f93cSkardel 	 * The signing method Samba will use is described by
144abb0f93cSkardel 	 * Microsoft in MS-SNTP, found here:
145abb0f93cSkardel 	 * http://msdn.microsoft.com/en-us/library/cc212930.aspx
146abb0f93cSkardel 	 */
147abb0f93cSkardel 
148abb0f93cSkardel 	int fd, sendlen;
149abb0f93cSkardel 	struct samba_key_in {
150abb0f93cSkardel 		uint32_t version;
151abb0f93cSkardel 		uint32_t op;
152abb0f93cSkardel 		uint32_t packet_id;
153abb0f93cSkardel 		uint32_t key_id_le;
154abb0f93cSkardel 		struct pkt pkt;
155abb0f93cSkardel 	} samba_pkt;
156abb0f93cSkardel 
157abb0f93cSkardel 	struct samba_key_out {
158abb0f93cSkardel 		uint32_t version;
159abb0f93cSkardel 		uint32_t op;
160abb0f93cSkardel 		uint32_t packet_id;
161abb0f93cSkardel 		struct pkt pkt;
162abb0f93cSkardel 	} samba_reply;
163abb0f93cSkardel 
164abb0f93cSkardel 	char full_socket[256];
165abb0f93cSkardel 
166abb0f93cSkardel 	char *reply = NULL;
167abb0f93cSkardel 	uint32_t reply_len;
168abb0f93cSkardel 
1698585484eSchristos 	ZERO(samba_pkt);
170abb0f93cSkardel 	samba_pkt.op = 0; /* Sign message */
171abb0f93cSkardel 	/* This will be echoed into the reply - a different
172abb0f93cSkardel 	 * impelementation might want multiple packets
173abb0f93cSkardel 	 * awaiting signing */
174abb0f93cSkardel 
175abb0f93cSkardel 	samba_pkt.packet_id = 1;
176abb0f93cSkardel 
177abb0f93cSkardel 	/* Swap the byte order back - it's actually little
178abb0f93cSkardel 	 * endian on the wire, but it was read above as
179abb0f93cSkardel 	 * network byte order */
180abb0f93cSkardel 	samba_pkt.key_id_le = htonl(xkeyid);
181abb0f93cSkardel 	samba_pkt.pkt = *xpkt;
182abb0f93cSkardel 
183abb0f93cSkardel 	snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
184abb0f93cSkardel 
185abb0f93cSkardel 	fd = ux_socket_connect(full_socket);
186abb0f93cSkardel 	/* Only continue with this if we can talk to Samba */
187abb0f93cSkardel 	if (fd != -1) {
188abb0f93cSkardel 		/* Send old packet to Samba, expect response */
189abb0f93cSkardel 		/* Packet to Samba is quite simple:
190abb0f93cSkardel 		   All values BIG endian except key ID as noted
191abb0f93cSkardel 		   [packet size as BE] - 4 bytes
192abb0f93cSkardel 		   [protocol version (0)] - 4 bytes
193abb0f93cSkardel 		   [packet ID] - 4 bytes
194abb0f93cSkardel 		   [operation (sign message=0)] - 4 bytes
195abb0f93cSkardel 		   [key id] - LITTLE endian (as on wire) - 4 bytes
196abb0f93cSkardel 		   [message to sign] - as marshalled, without signature
197abb0f93cSkardel 		*/
198abb0f93cSkardel 
199abb0f93cSkardel 		if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
200abb0f93cSkardel 			/* Huh?  could not talk to Samba... */
201abb0f93cSkardel 			close(fd);
202abb0f93cSkardel 			return;
203abb0f93cSkardel 		}
204abb0f93cSkardel 
205abb0f93cSkardel 		if (recv_packet(fd, &reply, &reply_len) != 0) {
206abb0f93cSkardel 			if (reply) {
207abb0f93cSkardel 				free(reply);
208abb0f93cSkardel 			}
209abb0f93cSkardel 			close(fd);
210abb0f93cSkardel 			return;
211abb0f93cSkardel 		}
212abb0f93cSkardel 		/* Return packet is also simple:
213abb0f93cSkardel 		   [packet size] - network byte order - 4 bytes
214abb0f93cSkardel 		   [protocol version (0)] network byte order - - 4 bytes
215abb0f93cSkardel 		   [operation (signed success=3, failure=4)] network byte order - - 4 byte
216abb0f93cSkardel 		   (optional) [signed message] - as provided before, with signature appended
217abb0f93cSkardel 		*/
218abb0f93cSkardel 
219abb0f93cSkardel 		if (reply_len <= sizeof(samba_reply)) {
220abb0f93cSkardel 			memcpy(&samba_reply, reply, reply_len);
221abb0f93cSkardel 			if (ntohl(samba_reply.op) == 3 && reply_len >  offsetof(struct samba_key_out, pkt)) {
222abb0f93cSkardel 				sendlen = reply_len - offsetof(struct samba_key_out, pkt);
223abb0f93cSkardel 				xpkt = &samba_reply.pkt;
224abb0f93cSkardel 				sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
225abb0f93cSkardel #ifdef DEBUG
226abb0f93cSkardel 				if (debug)
227abb0f93cSkardel 					printf(
228abb0f93cSkardel 						"transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
229abb0f93cSkardel 						current_time, ntoa(&rbufp->dstadr->sin),
230abb0f93cSkardel 						ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
231abb0f93cSkardel #endif
232abb0f93cSkardel 			}
233abb0f93cSkardel 		}
234abb0f93cSkardel 
235abb0f93cSkardel 		if (reply) {
236abb0f93cSkardel 			free(reply);
237abb0f93cSkardel 		}
238abb0f93cSkardel 		close(fd);
239abb0f93cSkardel 
240abb0f93cSkardel 	}
241abb0f93cSkardel }
242abb0f93cSkardel #endif
243