1 /* Copyright 2008, Red Hat, Inc.
2 Copyright 2008, Andrew Tridgell.
3 Licenced under the same terms as NTP itself.
13 #include "ntp_stdlib.h"
14 #include "ntp_unixtime.h"
15 #include "ntp_control.h"
16 #include "ntp_string.h"
23 #endif /* HAVE_LIBSCF_H */
27 /* socket routines by tridge - from junkcode.samba.org */
30 connect to a unix domain socket
33 ux_socket_connect(const char *name)
36 struct sockaddr_un addr;
42 addr.sun_family = AF_UNIX;
43 strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
45 fd = socket(AF_UNIX, SOCK_STREAM, 0);
50 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
60 keep writing until its all sent
63 write_all(int fd, const void *buf, size_t len)
67 int n = write(fd, buf, len);
68 if (n <= 0) return total;
69 buf = n + (char *)buf;
77 keep reading until its all read
80 read_all(int fd, void *buf, size_t len)
84 int n = read(fd, buf, len);
85 if (n <= 0) return total;
86 buf = n + (char *)buf;
94 send a packet in length prefix format
97 send_packet(int fd, const char *buf, uint32_t len)
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) != len) return -1;
106 receive a packet in length prefix format
109 recv_packet(int fd, char **buf, uint32_t *len)
111 if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
113 (*buf) = emalloc(*len);
114 if (read_all(fd, *buf, *len) != *len) {
123 struct recvbuf *rbufp, /* receive packet pointer */
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
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.
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
146 struct samba_key_in {
154 struct samba_key_out {
161 char full_socket[256];
167 samba_pkt.op = 0; /* Sign message */
168 /* This will be echoed into the reply - a different
169 * impelementation might want multiple packets
170 * awaiting signing */
172 samba_pkt.packet_id = 1;
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 samba_pkt.pkt = *xpkt;
180 snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
182 fd = ux_socket_connect(full_socket);
183 /* Only continue with this if we can talk to Samba */
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
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... */
202 if (recv_packet(fd, &reply, &reply_len) != 0) {
209 /* Return packet is also simple:
210 [packet size] - network byte order - 4 bytes
211 [protocol version (0)] network byte order - - 4 bytes
212 [operation (signed success=3, failure=4)] network byte order - - 4 byte
213 (optional) [signed message] - as provided before, with signature appended
216 if (reply_len <= sizeof(samba_reply)) {
217 memcpy(&samba_reply, reply, reply_len);
218 if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) {
219 sendlen = reply_len - offsetof(struct samba_key_out, pkt);
220 xpkt = &samba_reply.pkt;
221 sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
225 "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
226 current_time, ntoa(&rbufp->dstadr->sin),
227 ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);