Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / ntp_signd.c
blob35c14194b643fce7e8e6187fd0013304728503aa
1 /* $NetBSD$ */
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
11 #ifdef HAVE_NTP_SIGND
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"
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 */
27 #include <sys/un.h>
29 /* socket routines by tridge - from junkcode.samba.org */
32 connect to a unix domain socket
34 static int
35 ux_socket_connect(const char *name)
37 int fd;
38 struct sockaddr_un addr;
39 if (!name) {
40 return -1;
43 memset(&addr, 0, sizeof(addr));
44 addr.sun_family = AF_UNIX;
45 strncpy(addr.sun_path, name, sizeof(addr.sun_path));
47 fd = socket(AF_UNIX, SOCK_STREAM, 0);
48 if (fd == -1) {
49 return -1;
52 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
53 close(fd);
54 return -1;
57 return fd;
62 keep writing until its all sent
64 static int
65 write_all(int fd, const void *buf, size_t len)
67 size_t total = 0;
68 while (len) {
69 int n = write(fd, buf, len);
70 if (n <= 0) return total;
71 buf = n + (char *)buf;
72 len -= n;
73 total += n;
75 return total;
79 keep reading until its all read
81 static int
82 read_all(int fd, void *buf, size_t len)
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;
92 return total;
96 send a packet in length prefix format
98 static int
99 send_packet(int fd, const char *buf, uint32_t len)
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;
108 receive a packet in length prefix format
110 static int
111 recv_packet(int fd, char **buf, uint32_t *len)
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 return -1;
120 return 0;
123 void
124 send_via_ntp_signd(
125 struct recvbuf *rbufp, /* receive packet pointer */
126 int xmode,
127 keyid_t xkeyid,
128 int flags,
129 struct pkt *xpkt
133 /* We are here because it was detected that the client
134 * sent an all-zero signature, and we therefore know
135 * it's windows trying to talk to an AD server
137 * Because we don't want to dive into Samba's secrets
138 * database just to find the long-term kerberos key
139 * that is re-used as the NTP key, we instead hand the
140 * packet over to Samba to sign, and return to us.
142 * The signing method Samba will use is described by
143 * Microsoft in MS-SNTP, found here:
144 * http://msdn.microsoft.com/en-us/library/cc212930.aspx
147 int fd, sendlen;
148 struct samba_key_in {
149 uint32_t version;
150 uint32_t op;
151 uint32_t packet_id;
152 uint32_t key_id_le;
153 struct pkt pkt;
154 } samba_pkt;
156 struct samba_key_out {
157 uint32_t version;
158 uint32_t op;
159 uint32_t packet_id;
160 struct pkt pkt;
161 } samba_reply;
163 char full_socket[256];
165 char *reply = NULL;
166 uint32_t reply_len;
168 memset(&samba_pkt, 0, sizeof(samba_pkt));
169 samba_pkt.op = 0; /* Sign message */
170 /* This will be echoed into the reply - a different
171 * impelementation might want multiple packets
172 * awaiting signing */
174 samba_pkt.packet_id = 1;
176 /* Swap the byte order back - it's actually little
177 * endian on the wire, but it was read above as
178 * network byte order */
179 samba_pkt.key_id_le = htonl(xkeyid);
180 samba_pkt.pkt = *xpkt;
182 snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
184 fd = ux_socket_connect(full_socket);
185 /* Only continue with this if we can talk to Samba */
186 if (fd != -1) {
187 /* Send old packet to Samba, expect response */
188 /* Packet to Samba is quite simple:
189 All values BIG endian except key ID as noted
190 [packet size as BE] - 4 bytes
191 [protocol version (0)] - 4 bytes
192 [packet ID] - 4 bytes
193 [operation (sign message=0)] - 4 bytes
194 [key id] - LITTLE endian (as on wire) - 4 bytes
195 [message to sign] - as marshalled, without signature
198 if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
199 /* Huh? could not talk to Samba... */
200 close(fd);
201 return;
204 if (recv_packet(fd, &reply, &reply_len) != 0) {
205 if (reply) {
206 free(reply);
208 close(fd);
209 return;
211 /* Return packet is also simple:
212 [packet size] - network byte order - 4 bytes
213 [protocol version (0)] network byte order - - 4 bytes
214 [operation (signed success=3, failure=4)] network byte order - - 4 byte
215 (optional) [signed message] - as provided before, with signature appended
218 if (reply_len <= sizeof(samba_reply)) {
219 memcpy(&samba_reply, reply, reply_len);
220 if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) {
221 sendlen = reply_len - offsetof(struct samba_key_out, pkt);
222 xpkt = &samba_reply.pkt;
223 sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
224 #ifdef DEBUG
225 if (debug)
226 printf(
227 "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
228 current_time, ntoa(&rbufp->dstadr->sin),
229 ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
230 #endif
234 if (reply) {
235 free(reply);
237 close(fd);
241 #endif