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