12b15cb3dSCy Schubert /* Copyright 2008, Red Hat, Inc.
22b15cb3dSCy Schubert Copyright 2008, Andrew Tridgell.
32b15cb3dSCy Schubert Licenced under the same terms as NTP itself.
42b15cb3dSCy Schubert */
52b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
62b15cb3dSCy Schubert #include <config.h>
72b15cb3dSCy Schubert #endif
82b15cb3dSCy Schubert
92b15cb3dSCy Schubert #ifdef HAVE_NTP_SIGND
102b15cb3dSCy Schubert
112b15cb3dSCy Schubert #include "ntpd.h"
122b15cb3dSCy Schubert #include "ntp_io.h"
132b15cb3dSCy Schubert #include "ntp_stdlib.h"
142b15cb3dSCy Schubert #include "ntp_unixtime.h"
152b15cb3dSCy Schubert #include "ntp_control.h"
162b15cb3dSCy Schubert #include "ntp_string.h"
172b15cb3dSCy Schubert
182b15cb3dSCy Schubert #include <stdio.h>
192b15cb3dSCy Schubert #include <stddef.h>
202b15cb3dSCy Schubert #ifdef HAVE_LIBSCF_H
212b15cb3dSCy Schubert #include <libscf.h>
222b15cb3dSCy Schubert #include <unistd.h>
232b15cb3dSCy Schubert #endif /* HAVE_LIBSCF_H */
242b15cb3dSCy Schubert
252b15cb3dSCy Schubert #include <sys/un.h>
262b15cb3dSCy Schubert
272b15cb3dSCy Schubert /* socket routines by tridge - from junkcode.samba.org */
282b15cb3dSCy Schubert
292b15cb3dSCy Schubert /*
302b15cb3dSCy Schubert connect to a unix domain socket
312b15cb3dSCy Schubert */
322b15cb3dSCy Schubert static int
ux_socket_connect(const char * name)332b15cb3dSCy Schubert ux_socket_connect(const char *name)
342b15cb3dSCy Schubert {
352b15cb3dSCy Schubert int fd;
362b15cb3dSCy Schubert struct sockaddr_un addr;
372b15cb3dSCy Schubert if (!name) {
382b15cb3dSCy Schubert return -1;
392b15cb3dSCy Schubert }
402b15cb3dSCy Schubert
412b15cb3dSCy Schubert ZERO(addr);
422b15cb3dSCy Schubert addr.sun_family = AF_UNIX;
432b15cb3dSCy Schubert strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
442b15cb3dSCy Schubert
452b15cb3dSCy Schubert fd = socket(AF_UNIX, SOCK_STREAM, 0);
462b15cb3dSCy Schubert if (fd == -1) {
472b15cb3dSCy Schubert return -1;
482b15cb3dSCy Schubert }
492b15cb3dSCy Schubert
502b15cb3dSCy Schubert if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
512b15cb3dSCy Schubert close(fd);
522b15cb3dSCy Schubert return -1;
532b15cb3dSCy Schubert }
542b15cb3dSCy Schubert
552b15cb3dSCy Schubert return fd;
562b15cb3dSCy Schubert }
572b15cb3dSCy Schubert
582b15cb3dSCy Schubert
592b15cb3dSCy Schubert /*
602b15cb3dSCy Schubert keep writing until its all sent
612b15cb3dSCy Schubert */
622b15cb3dSCy Schubert static int
write_all(int fd,const void * buf,size_t len)632b15cb3dSCy Schubert write_all(int fd, const void *buf, size_t len)
642b15cb3dSCy Schubert {
652b15cb3dSCy Schubert size_t total = 0;
662b15cb3dSCy Schubert while (len) {
672b15cb3dSCy Schubert int n = write(fd, buf, len);
682b15cb3dSCy Schubert if (n <= 0) return total;
69*3311ff84SXin LI buf = n + (const char *)buf;
702b15cb3dSCy Schubert len -= n;
712b15cb3dSCy Schubert total += n;
722b15cb3dSCy Schubert }
732b15cb3dSCy Schubert return total;
742b15cb3dSCy Schubert }
752b15cb3dSCy Schubert
762b15cb3dSCy Schubert /*
772b15cb3dSCy Schubert keep reading until its all read
782b15cb3dSCy Schubert */
792b15cb3dSCy Schubert static int
read_all(int fd,void * buf,size_t len)802b15cb3dSCy Schubert read_all(int fd, void *buf, size_t len)
812b15cb3dSCy Schubert {
822b15cb3dSCy Schubert size_t total = 0;
832b15cb3dSCy Schubert while (len) {
842b15cb3dSCy Schubert int n = read(fd, buf, len);
852b15cb3dSCy Schubert if (n <= 0) return total;
862b15cb3dSCy Schubert buf = n + (char *)buf;
872b15cb3dSCy Schubert len -= n;
882b15cb3dSCy Schubert total += n;
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert return total;
912b15cb3dSCy Schubert }
922b15cb3dSCy Schubert
932b15cb3dSCy Schubert /*
942b15cb3dSCy Schubert send a packet in length prefix format
952b15cb3dSCy Schubert */
962b15cb3dSCy Schubert static int
send_packet(int fd,const char * buf,uint32_t len)972b15cb3dSCy Schubert send_packet(int fd, const char *buf, uint32_t len)
982b15cb3dSCy Schubert {
992b15cb3dSCy Schubert uint32_t net_len = htonl(len);
1002b15cb3dSCy Schubert if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1;
1012b15cb3dSCy Schubert if (write_all(fd, buf, len) != len) return -1;
1022b15cb3dSCy Schubert return 0;
1032b15cb3dSCy Schubert }
1042b15cb3dSCy Schubert
1052b15cb3dSCy Schubert /*
1062b15cb3dSCy Schubert receive a packet in length prefix format
1072b15cb3dSCy Schubert */
1082b15cb3dSCy Schubert static int
recv_packet(int fd,char ** buf,uint32_t * len)1092b15cb3dSCy Schubert recv_packet(int fd, char **buf, uint32_t *len)
1102b15cb3dSCy Schubert {
1112b15cb3dSCy Schubert if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
1122b15cb3dSCy Schubert *len = ntohl(*len);
113*3311ff84SXin LI *buf = emalloc(*len);
1142b15cb3dSCy Schubert if (read_all(fd, *buf, *len) != *len) {
1152b15cb3dSCy Schubert free(*buf);
116*3311ff84SXin LI *buf = NULL;
1172b15cb3dSCy Schubert return -1;
1182b15cb3dSCy Schubert }
1192b15cb3dSCy Schubert return 0;
1202b15cb3dSCy Schubert }
1212b15cb3dSCy Schubert
1222b15cb3dSCy Schubert void
send_via_ntp_signd(struct recvbuf * rbufp,int xmode,keyid_t xkeyid,int flags,struct pkt * xpkt)1232b15cb3dSCy Schubert send_via_ntp_signd(
1242b15cb3dSCy Schubert struct recvbuf *rbufp, /* receive packet pointer */
1252b15cb3dSCy Schubert int xmode,
1262b15cb3dSCy Schubert keyid_t xkeyid,
1272b15cb3dSCy Schubert int flags,
1282b15cb3dSCy Schubert struct pkt *xpkt
1292b15cb3dSCy Schubert )
1302b15cb3dSCy Schubert {
1312b15cb3dSCy Schubert
1322b15cb3dSCy Schubert /* We are here because it was detected that the client
1332b15cb3dSCy Schubert * sent an all-zero signature, and we therefore know
1342b15cb3dSCy Schubert * it's windows trying to talk to an AD server
1352b15cb3dSCy Schubert *
1362b15cb3dSCy Schubert * Because we don't want to dive into Samba's secrets
1372b15cb3dSCy Schubert * database just to find the long-term kerberos key
1382b15cb3dSCy Schubert * that is re-used as the NTP key, we instead hand the
1392b15cb3dSCy Schubert * packet over to Samba to sign, and return to us.
1402b15cb3dSCy Schubert *
1412b15cb3dSCy Schubert * The signing method Samba will use is described by
1422b15cb3dSCy Schubert * Microsoft in MS-SNTP, found here:
1432b15cb3dSCy Schubert * http://msdn.microsoft.com/en-us/library/cc212930.aspx
1442b15cb3dSCy Schubert */
1452b15cb3dSCy Schubert
1462b15cb3dSCy Schubert int fd, sendlen;
1472b15cb3dSCy Schubert struct samba_key_in {
1482b15cb3dSCy Schubert uint32_t version;
1492b15cb3dSCy Schubert uint32_t op;
1502b15cb3dSCy Schubert uint32_t packet_id;
1512b15cb3dSCy Schubert uint32_t key_id_le;
1522b15cb3dSCy Schubert struct pkt pkt;
1532b15cb3dSCy Schubert } samba_pkt;
1542b15cb3dSCy Schubert
1552b15cb3dSCy Schubert struct samba_key_out {
1562b15cb3dSCy Schubert uint32_t version;
1572b15cb3dSCy Schubert uint32_t op;
1582b15cb3dSCy Schubert uint32_t packet_id;
1592b15cb3dSCy Schubert struct pkt pkt;
1602b15cb3dSCy Schubert } samba_reply;
1612b15cb3dSCy Schubert
1622b15cb3dSCy Schubert char full_socket[256];
1632b15cb3dSCy Schubert
1642b15cb3dSCy Schubert char *reply = NULL;
1652b15cb3dSCy Schubert uint32_t reply_len;
1662b15cb3dSCy Schubert
1672b15cb3dSCy Schubert ZERO(samba_pkt);
1682b15cb3dSCy Schubert samba_pkt.op = 0; /* Sign message */
1692b15cb3dSCy Schubert /* This will be echoed into the reply - a different
1702b15cb3dSCy Schubert * impelementation might want multiple packets
1712b15cb3dSCy Schubert * awaiting signing */
1722b15cb3dSCy Schubert
1732b15cb3dSCy Schubert samba_pkt.packet_id = 1;
1742b15cb3dSCy Schubert
1752b15cb3dSCy Schubert /* Swap the byte order back - it's actually little
1762b15cb3dSCy Schubert * endian on the wire, but it was read above as
1772b15cb3dSCy Schubert * network byte order */
1782b15cb3dSCy Schubert samba_pkt.key_id_le = htonl(xkeyid);
1792b15cb3dSCy Schubert samba_pkt.pkt = *xpkt;
1802b15cb3dSCy Schubert
1812b15cb3dSCy Schubert snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket);
1822b15cb3dSCy Schubert
1832b15cb3dSCy Schubert fd = ux_socket_connect(full_socket);
1842b15cb3dSCy Schubert /* Only continue with this if we can talk to Samba */
1852b15cb3dSCy Schubert if (fd != -1) {
1862b15cb3dSCy Schubert /* Send old packet to Samba, expect response */
1872b15cb3dSCy Schubert /* Packet to Samba is quite simple:
1882b15cb3dSCy Schubert All values BIG endian except key ID as noted
1892b15cb3dSCy Schubert [packet size as BE] - 4 bytes
1902b15cb3dSCy Schubert [protocol version (0)] - 4 bytes
1912b15cb3dSCy Schubert [packet ID] - 4 bytes
1922b15cb3dSCy Schubert [operation (sign message=0)] - 4 bytes
1932b15cb3dSCy Schubert [key id] - LITTLE endian (as on wire) - 4 bytes
1942b15cb3dSCy Schubert [message to sign] - as marshalled, without signature
1952b15cb3dSCy Schubert */
1962b15cb3dSCy Schubert
1972b15cb3dSCy Schubert if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) {
1982b15cb3dSCy Schubert /* Huh? could not talk to Samba... */
1992b15cb3dSCy Schubert close(fd);
2002b15cb3dSCy Schubert return;
2012b15cb3dSCy Schubert }
2022b15cb3dSCy Schubert
2032b15cb3dSCy Schubert if (recv_packet(fd, &reply, &reply_len) != 0) {
2042b15cb3dSCy Schubert if (reply) {
2052b15cb3dSCy Schubert free(reply);
2062b15cb3dSCy Schubert }
2072b15cb3dSCy Schubert close(fd);
2082b15cb3dSCy Schubert return;
2092b15cb3dSCy Schubert }
2102b15cb3dSCy Schubert /* Return packet is also simple:
2112b15cb3dSCy Schubert [packet size] - network byte order - 4 bytes
2122b15cb3dSCy Schubert [protocol version (0)] network byte order - - 4 bytes
2132b15cb3dSCy Schubert [operation (signed success=3, failure=4)] network byte order - - 4 byte
2142b15cb3dSCy Schubert (optional) [signed message] - as provided before, with signature appended
2152b15cb3dSCy Schubert */
2162b15cb3dSCy Schubert
2172b15cb3dSCy Schubert if (reply_len <= sizeof(samba_reply)) {
2182b15cb3dSCy Schubert memcpy(&samba_reply, reply, reply_len);
2192b15cb3dSCy Schubert if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) {
2202b15cb3dSCy Schubert sendlen = reply_len - offsetof(struct samba_key_out, pkt);
2212b15cb3dSCy Schubert xpkt = &samba_reply.pkt;
2222b15cb3dSCy Schubert sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen);
2232b15cb3dSCy Schubert #ifdef DEBUG
2242b15cb3dSCy Schubert if (debug)
2252b15cb3dSCy Schubert printf(
2262b15cb3dSCy Schubert "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n",
2272b15cb3dSCy Schubert current_time, ntoa(&rbufp->dstadr->sin),
2282b15cb3dSCy Schubert ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
2292b15cb3dSCy Schubert #endif
2302b15cb3dSCy Schubert }
2312b15cb3dSCy Schubert }
2322b15cb3dSCy Schubert
2332b15cb3dSCy Schubert if (reply) {
2342b15cb3dSCy Schubert free(reply);
2352b15cb3dSCy Schubert }
2362b15cb3dSCy Schubert close(fd);
2372b15cb3dSCy Schubert
2382b15cb3dSCy Schubert }
2392b15cb3dSCy Schubert }
2402b15cb3dSCy Schubert #endif
241