1 /* Copyright 2008, Red Hat, Inc.
2 Copyright 2008, Andrew Tridgell.
3 Licenced under the same terms as NTP itself.
4 */
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #ifdef HAVE_NTP_SIGND
10
11 #include "ntpd.h"
12 #include "ntp_io.h"
13 #include "ntp_stdlib.h"
14 #include "ntp_unixtime.h"
15 #include "ntp_control.h"
16 #include "ntp_string.h"
17
18 #include <stdio.h>
19 #include <stddef.h>
20 #ifdef HAVE_LIBSCF_H
21 #include <libscf.h>
22 #include <unistd.h>
23 #endif /* HAVE_LIBSCF_H */
24
25 #include <sys/un.h>
26
27 /* socket routines by tridge - from junkcode.samba.org */
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 -= n;
71 total += 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 -= n;
88 total += 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) != 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) != *len) {
115 free(*buf);
116 *buf = NULL;
117 return -1;
118 }
119 return 0;
120 }
121
122 void
send_via_ntp_signd(struct recvbuf * rbufp,int xmode,keyid_t xkeyid,int flags,struct pkt * xpkt)123 send_via_ntp_signd(
124 struct recvbuf *rbufp, /* receive packet pointer */
125 int xmode,
126 keyid_t xkeyid,
127 int flags,
128 struct pkt *xpkt
129 )
130 {
131
132 /* We are here because it was detected that the client
133 * sent an all-zero signature, and we therefore know
134 * it's windows trying to talk to an AD server
135 *
136 * Because we don't want to dive into Samba's secrets
137 * database just to find the long-term kerberos key
138 * that is re-used as the NTP key, we instead hand the
139 * packet over to Samba to sign, and return to us.
140 *
141 * The signing method Samba will use is described by
142 * Microsoft in MS-SNTP, found here:
143 * http://msdn.microsoft.com/en-us/library/cc212930.aspx
144 */
145
146 int fd, sendlen;
147 struct samba_key_in {
148 uint32_t version;
149 uint32_t op;
150 uint32_t packet_id;
151 uint32_t key_id_le;
152 struct pkt pkt;
153 } samba_pkt;
154
155 struct samba_key_out {
156 uint32_t version;
157 uint32_t op;
158 uint32_t packet_id;
159 struct pkt pkt;
160 } samba_reply;
161
162 char full_socket[256];
163
164 char *reply = NULL;
165 uint32_t reply_len;
166
167 ZERO(samba_pkt);
168 samba_pkt.op = 0; /* Sign message */
169 /* This will be echoed into the reply - a different
170 * impelementation might want multiple packets
171 * awaiting signing */
172
173 samba_pkt.packet_id = 1;
174
175 /* Swap the byte order back - it's actually little
176 * endian on the wire, but it was read above as
177 * network byte order */
178 samba_pkt.key_id_le = htonl(xkeyid);
179 samba_pkt.pkt = *xpkt;
180
181 snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
182
183 fd = ux_socket_connect(full_socket);
184 /* Only continue with this if we can talk to Samba */
185 if (fd != -1) {
186 /* Send old packet to Samba, expect response */
187 /* Packet to Samba is quite simple:
188 All values BIG endian except key ID as noted
189 [packet size as BE] - 4 bytes
190 [protocol version (0)] - 4 bytes
191 [packet ID] - 4 bytes
192 [operation (sign message=0)] - 4 bytes
193 [key id] - LITTLE endian (as on wire) - 4 bytes
194 [message to sign] - as marshalled, without signature
195 */
196
197 if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
198 /* Huh? could not talk to Samba... */
199 close(fd);
200 return;
201 }
202
203 if (recv_packet(fd, &reply, &reply_len) != 0) {
204 if (reply) {
205 free(reply);
206 }
207 close(fd);
208 return;
209 }
210 /* Return packet is also simple:
211 [packet size] - network byte order - 4 bytes
212 [protocol version (0)] network byte order - - 4 bytes
213 [operation (signed success=3, failure=4)] network byte order - - 4 byte
214 (optional) [signed message] - as provided before, with signature appended
215 */
216
217 if (reply_len <= sizeof(samba_reply)) {
218 memcpy(&samba_reply, reply, reply_len);
219 if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) {
220 sendlen = reply_len - offsetof(struct samba_key_out, pkt);
221 xpkt = &samba_reply.pkt;
222 sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
223 #ifdef DEBUG
224 if (debug)
225 printf(
226 "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
227 current_time, ntoa(&rbufp->dstadr->sin),
228 ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
229 #endif
230 }
231 }
232
233 if (reply) {
234 free(reply);
235 }
236 close(fd);
237
238 }
239 }
240 #endif
241