1258945Sroberto/* Copyright 2008, Red Hat, Inc. 2258945Sroberto Copyright 2008, Andrew Tridgell. 3258945Sroberto Licenced under the same terms as NTP itself. 4258945Sroberto */ 5258945Sroberto#ifdef HAVE_CONFIG_H 6258945Sroberto#include <config.h> 7258945Sroberto#endif 8258945Sroberto 9258945Sroberto#ifdef HAVE_NTP_SIGND 10258945Sroberto 11258945Sroberto#include "ntpd.h" 12258945Sroberto#include "ntp_io.h" 13258945Sroberto#include "ntp_stdlib.h" 14258945Sroberto#include "ntp_unixtime.h" 15258945Sroberto#include "ntp_control.h" 16258945Sroberto#include "ntp_string.h" 17258945Sroberto 18258945Sroberto#include <stdio.h> 19258945Sroberto#include <stddef.h> 20258945Sroberto#ifdef HAVE_LIBSCF_H 21258945Sroberto#include <libscf.h> 22258945Sroberto#include <unistd.h> 23258945Sroberto#endif /* HAVE_LIBSCF_H */ 24258945Sroberto 25258945Sroberto#include <sys/un.h> 26258945Sroberto 27258945Sroberto/* socket routines by tridge - from junkcode.samba.org */ 28258945Sroberto 29258945Sroberto/* 30258945Sroberto connect to a unix domain socket 31258945Sroberto*/ 32258945Srobertostatic int 33258945Srobertoux_socket_connect(const char *name) 34258945Sroberto{ 35258945Sroberto int fd; 36280849Scy struct sockaddr_un addr; 37258945Sroberto if (!name) { 38258945Sroberto return -1; 39258945Sroberto } 40258945Sroberto 41280849Scy ZERO(addr); 42280849Scy addr.sun_family = AF_UNIX; 43280849Scy strlcpy(addr.sun_path, name, sizeof(addr.sun_path)); 44258945Sroberto 45258945Sroberto fd = socket(AF_UNIX, SOCK_STREAM, 0); 46258945Sroberto if (fd == -1) { 47258945Sroberto return -1; 48258945Sroberto } 49258945Sroberto 50258945Sroberto if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 51258945Sroberto close(fd); 52258945Sroberto return -1; 53258945Sroberto } 54258945Sroberto 55258945Sroberto return fd; 56258945Sroberto} 57258945Sroberto 58258945Sroberto 59258945Sroberto/* 60258945Sroberto keep writing until its all sent 61258945Sroberto*/ 62258945Srobertostatic int 63258945Srobertowrite_all(int fd, const void *buf, size_t len) 64258945Sroberto{ 65258945Sroberto size_t total = 0; 66258945Sroberto while (len) { 67258945Sroberto int n = write(fd, buf, len); 68258945Sroberto if (n <= 0) return total; 69293423Sdelphij buf = n + (const char *)buf; 70258945Sroberto len -= n; 71258945Sroberto total += n; 72258945Sroberto } 73258945Sroberto return total; 74258945Sroberto} 75258945Sroberto 76258945Sroberto/* 77258945Sroberto keep reading until its all read 78258945Sroberto*/ 79258945Srobertostatic int 80258945Srobertoread_all(int fd, void *buf, size_t len) 81258945Sroberto{ 82258945Sroberto size_t total = 0; 83258945Sroberto while (len) { 84258945Sroberto int n = read(fd, buf, len); 85258945Sroberto if (n <= 0) return total; 86258945Sroberto buf = n + (char *)buf; 87258945Sroberto len -= n; 88258945Sroberto total += n; 89258945Sroberto } 90258945Sroberto return total; 91258945Sroberto} 92258945Sroberto 93258945Sroberto/* 94258945Sroberto send a packet in length prefix format 95258945Sroberto*/ 96258945Srobertostatic int 97258945Srobertosend_packet(int fd, const char *buf, uint32_t len) 98258945Sroberto{ 99258945Sroberto uint32_t net_len = htonl(len); 100258945Sroberto if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1; 101258945Sroberto if (write_all(fd, buf, len) != len) return -1; 102258945Sroberto return 0; 103258945Sroberto} 104258945Sroberto 105258945Sroberto/* 106258945Sroberto receive a packet in length prefix format 107258945Sroberto*/ 108258945Srobertostatic int 109258945Srobertorecv_packet(int fd, char **buf, uint32_t *len) 110258945Sroberto{ 111258945Sroberto if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1; 112258945Sroberto *len = ntohl(*len); 113293423Sdelphij *buf = emalloc(*len); 114258945Sroberto if (read_all(fd, *buf, *len) != *len) { 115258945Sroberto free(*buf); 116293423Sdelphij *buf = NULL; 117258945Sroberto return -1; 118258945Sroberto } 119258945Sroberto return 0; 120258945Sroberto} 121258945Sroberto 122258945Srobertovoid 123258945Srobertosend_via_ntp_signd( 124258945Sroberto struct recvbuf *rbufp, /* receive packet pointer */ 125258945Sroberto int xmode, 126258945Sroberto keyid_t xkeyid, 127258945Sroberto int flags, 128258945Sroberto struct pkt *xpkt 129258945Sroberto ) 130258945Sroberto{ 131258945Sroberto 132258945Sroberto /* We are here because it was detected that the client 133258945Sroberto * sent an all-zero signature, and we therefore know 134258945Sroberto * it's windows trying to talk to an AD server 135258945Sroberto * 136258945Sroberto * Because we don't want to dive into Samba's secrets 137258945Sroberto * database just to find the long-term kerberos key 138258945Sroberto * that is re-used as the NTP key, we instead hand the 139258945Sroberto * packet over to Samba to sign, and return to us. 140258945Sroberto * 141258945Sroberto * The signing method Samba will use is described by 142258945Sroberto * Microsoft in MS-SNTP, found here: 143258945Sroberto * http://msdn.microsoft.com/en-us/library/cc212930.aspx 144258945Sroberto */ 145258945Sroberto 146258945Sroberto int fd, sendlen; 147258945Sroberto struct samba_key_in { 148258945Sroberto uint32_t version; 149258945Sroberto uint32_t op; 150258945Sroberto uint32_t packet_id; 151258945Sroberto uint32_t key_id_le; 152258945Sroberto struct pkt pkt; 153258945Sroberto } samba_pkt; 154258945Sroberto 155258945Sroberto struct samba_key_out { 156258945Sroberto uint32_t version; 157258945Sroberto uint32_t op; 158258945Sroberto uint32_t packet_id; 159258945Sroberto struct pkt pkt; 160258945Sroberto } samba_reply; 161258945Sroberto 162258945Sroberto char full_socket[256]; 163258945Sroberto 164258945Sroberto char *reply = NULL; 165258945Sroberto uint32_t reply_len; 166258945Sroberto 167280849Scy ZERO(samba_pkt); 168258945Sroberto samba_pkt.op = 0; /* Sign message */ 169258945Sroberto /* This will be echoed into the reply - a different 170258945Sroberto * impelementation might want multiple packets 171258945Sroberto * awaiting signing */ 172258945Sroberto 173258945Sroberto samba_pkt.packet_id = 1; 174258945Sroberto 175258945Sroberto /* Swap the byte order back - it's actually little 176258945Sroberto * endian on the wire, but it was read above as 177258945Sroberto * network byte order */ 178258945Sroberto samba_pkt.key_id_le = htonl(xkeyid); 179258945Sroberto samba_pkt.pkt = *xpkt; 180258945Sroberto 181258945Sroberto snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket); 182258945Sroberto 183258945Sroberto fd = ux_socket_connect(full_socket); 184258945Sroberto /* Only continue with this if we can talk to Samba */ 185258945Sroberto if (fd != -1) { 186258945Sroberto /* Send old packet to Samba, expect response */ 187258945Sroberto /* Packet to Samba is quite simple: 188258945Sroberto All values BIG endian except key ID as noted 189258945Sroberto [packet size as BE] - 4 bytes 190258945Sroberto [protocol version (0)] - 4 bytes 191258945Sroberto [packet ID] - 4 bytes 192258945Sroberto [operation (sign message=0)] - 4 bytes 193258945Sroberto [key id] - LITTLE endian (as on wire) - 4 bytes 194258945Sroberto [message to sign] - as marshalled, without signature 195258945Sroberto */ 196258945Sroberto 197258945Sroberto if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) { 198258945Sroberto /* Huh? could not talk to Samba... */ 199258945Sroberto close(fd); 200258945Sroberto return; 201258945Sroberto } 202258945Sroberto 203258945Sroberto if (recv_packet(fd, &reply, &reply_len) != 0) { 204258945Sroberto if (reply) { 205258945Sroberto free(reply); 206258945Sroberto } 207258945Sroberto close(fd); 208258945Sroberto return; 209258945Sroberto } 210258945Sroberto /* Return packet is also simple: 211258945Sroberto [packet size] - network byte order - 4 bytes 212258945Sroberto [protocol version (0)] network byte order - - 4 bytes 213258945Sroberto [operation (signed success=3, failure=4)] network byte order - - 4 byte 214258945Sroberto (optional) [signed message] - as provided before, with signature appended 215258945Sroberto */ 216258945Sroberto 217258945Sroberto if (reply_len <= sizeof(samba_reply)) { 218258945Sroberto memcpy(&samba_reply, reply, reply_len); 219258945Sroberto if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) { 220258945Sroberto sendlen = reply_len - offsetof(struct samba_key_out, pkt); 221258945Sroberto xpkt = &samba_reply.pkt; 222258945Sroberto sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen); 223258945Sroberto#ifdef DEBUG 224258945Sroberto if (debug) 225258945Sroberto printf( 226258945Sroberto "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n", 227258945Sroberto current_time, ntoa(&rbufp->dstadr->sin), 228258945Sroberto ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen); 229258945Sroberto#endif 230258945Sroberto } 231258945Sroberto } 232258945Sroberto 233258945Sroberto if (reply) { 234258945Sroberto free(reply); 235258945Sroberto } 236258945Sroberto close(fd); 237258945Sroberto 238258945Sroberto } 239258945Sroberto} 240258945Sroberto#endif 241