]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/ntpd/ntp_signd.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / ntpd / ntp_signd.c
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 
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 
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 + (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 
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 
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 
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                 return -1;
117         }
118         return 0;
119 }
120
121 void 
122 send_via_ntp_signd(
123         struct recvbuf *rbufp,  /* receive packet pointer */
124         int     xmode,
125         keyid_t xkeyid, 
126         int flags,
127         struct pkt  *xpkt
128         )
129 {
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                 struct pkt pkt;
152         } samba_pkt;
153         
154         struct samba_key_out {
155                 uint32_t version;
156                 uint32_t op;
157                 uint32_t packet_id;
158                 struct pkt pkt;
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          * impelementation 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         samba_pkt.pkt = *xpkt;
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                         if (reply) {
204                                 free(reply);
205                         }
206                         close(fd);
207                         return;
208                 }
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
214                 */
215                         
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);
222 #ifdef DEBUG
223                                 if (debug)
224                                         printf(
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);
228 #endif
229                         }
230                 }
231                 
232                 if (reply) {
233                         free(reply);
234                 }
235                 close(fd);
236                 
237         }
238 }
239 #endif