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