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