ntp_signd.c revision 280849
1293734Sarybchik/* Copyright 2008, Red Hat, Inc. 2293734Sarybchik Copyright 2008, Andrew Tridgell. 3293734Sarybchik Licenced under the same terms as NTP itself. 4293734Sarybchik */ 5293734Sarybchik#ifdef HAVE_CONFIG_H 6293734Sarybchik#include <config.h> 7293734Sarybchik#endif 8293734Sarybchik 9293734Sarybchik#ifdef HAVE_NTP_SIGND 10293734Sarybchik 11293734Sarybchik#include "ntpd.h" 12293734Sarybchik#include "ntp_io.h" 13293734Sarybchik#include "ntp_stdlib.h" 14293734Sarybchik#include "ntp_unixtime.h" 15293734Sarybchik#include "ntp_control.h" 16293734Sarybchik#include "ntp_string.h" 17293734Sarybchik 18293734Sarybchik#include <stdio.h> 19293734Sarybchik#include <stddef.h> 20293734Sarybchik#ifdef HAVE_LIBSCF_H 21293734Sarybchik#include <libscf.h> 22293734Sarybchik#include <unistd.h> 23293734Sarybchik#endif /* HAVE_LIBSCF_H */ 24293734Sarybchik 25293734Sarybchik#include <sys/un.h> 26293734Sarybchik 27293734Sarybchik/* socket routines by tridge - from junkcode.samba.org */ 28293734Sarybchik 29293734Sarybchik/* 30293734Sarybchik connect to a unix domain socket 31293734Sarybchik*/ 32293734Sarybchikstatic int 33293734Sarybchikux_socket_connect(const char *name) 34293734Sarybchik{ 35293734Sarybchik int fd; 36293734Sarybchik struct sockaddr_un addr; 37293734Sarybchik if (!name) { 38293734Sarybchik return -1; 39293734Sarybchik } 40293748Sarybchik 41293748Sarybchik ZERO(addr); 42293748Sarybchik addr.sun_family = AF_UNIX; 43293748Sarybchik strlcpy(addr.sun_path, name, sizeof(addr.sun_path)); 44293748Sarybchik 45293748Sarybchik fd = socket(AF_UNIX, SOCK_STREAM, 0); 46293748Sarybchik if (fd == -1) { 47293734Sarybchik return -1; 48299720Sarybchik } 49299720Sarybchik 50299720Sarybchik if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 51299720Sarybchik close(fd); 52299720Sarybchik return -1; 53299720Sarybchik } 54299720Sarybchik 55299720Sarybchik return fd; 56299720Sarybchik} 57299720Sarybchik 58299720Sarybchik 59299720Sarybchik/* 60299720Sarybchik keep writing until its all sent 61299720Sarybchik*/ 62299720Sarybchikstatic int 63299720Sarybchikwrite_all(int fd, const void *buf, size_t len) 64299720Sarybchik{ 65299720Sarybchik size_t total = 0; 66299720Sarybchik while (len) { 67299720Sarybchik int n = write(fd, buf, len); 68299720Sarybchik if (n <= 0) return total; 69299720Sarybchik buf = n + (char *)buf; 70299720Sarybchik len -= n; 71299720Sarybchik total += n; 72299720Sarybchik } 73299720Sarybchik return total; 74299720Sarybchik} 75299720Sarybchik 76299720Sarybchik/* 77299720Sarybchik keep reading until its all read 78299720Sarybchik*/ 79299720Sarybchikstatic int 80299720Sarybchikread_all(int fd, void *buf, size_t len) 81299720Sarybchik{ 82299720Sarybchik size_t total = 0; 83299720Sarybchik while (len) { 84299720Sarybchik int n = read(fd, buf, len); 85299720Sarybchik if (n <= 0) return total; 86299720Sarybchik buf = n + (char *)buf; 87299720Sarybchik len -= n; 88299720Sarybchik total += n; 89299720Sarybchik } 90299720Sarybchik return total; 91299720Sarybchik} 92299720Sarybchik 93299720Sarybchik/* 94299720Sarybchik send a packet in length prefix format 95299720Sarybchik*/ 96299720Sarybchikstatic int 97299720Sarybchiksend_packet(int fd, const char *buf, uint32_t len) 98299720Sarybchik{ 99299720Sarybchik uint32_t net_len = htonl(len); 100299720Sarybchik if (write_all(fd, &net_len, sizeof(net_len)) != sizeof(net_len)) return -1; 101299720Sarybchik if (write_all(fd, buf, len) != len) return -1; 102299720Sarybchik return 0; 103299720Sarybchik} 104299720Sarybchik 105299720Sarybchik/* 106299720Sarybchik receive a packet in length prefix format 107299720Sarybchik*/ 108299720Sarybchikstatic int 109299720Sarybchikrecv_packet(int fd, char **buf, uint32_t *len) 110299720Sarybchik{ 111299720Sarybchik if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1; 112299720Sarybchik *len = ntohl(*len); 113299720Sarybchik (*buf) = emalloc(*len); 114299720Sarybchik if (read_all(fd, *buf, *len) != *len) { 115299720Sarybchik free(*buf); 116299720Sarybchik return -1; 117299720Sarybchik } 118299720Sarybchik return 0; 119299720Sarybchik} 120299720Sarybchik 121299720Sarybchikvoid 122299720Sarybchiksend_via_ntp_signd( 123299720Sarybchik struct recvbuf *rbufp, /* receive packet pointer */ 124299720Sarybchik int xmode, 125299720Sarybchik keyid_t xkeyid, 126299720Sarybchik int flags, 127299720Sarybchik struct pkt *xpkt 128299720Sarybchik ) 129299720Sarybchik{ 130299720Sarybchik 131299720Sarybchik /* We are here because it was detected that the client 132299720Sarybchik * sent an all-zero signature, and we therefore know 133299720Sarybchik * it's windows trying to talk to an AD server 134299720Sarybchik * 135299720Sarybchik * Because we don't want to dive into Samba's secrets 136299720Sarybchik * database just to find the long-term kerberos key 137299720Sarybchik * that is re-used as the NTP key, we instead hand the 138299720Sarybchik * packet over to Samba to sign, and return to us. 139299720Sarybchik * 140299720Sarybchik * The signing method Samba will use is described by 141299720Sarybchik * Microsoft in MS-SNTP, found here: 142299720Sarybchik * http://msdn.microsoft.com/en-us/library/cc212930.aspx 143299720Sarybchik */ 144299720Sarybchik 145299720Sarybchik int fd, sendlen; 146299720Sarybchik struct samba_key_in { 147299720Sarybchik uint32_t version; 148299720Sarybchik uint32_t op; 149299720Sarybchik uint32_t packet_id; 150299720Sarybchik uint32_t key_id_le; 151299720Sarybchik struct pkt pkt; 152299720Sarybchik } samba_pkt; 153299720Sarybchik 154299720Sarybchik struct samba_key_out { 155299720Sarybchik uint32_t version; 156299720Sarybchik uint32_t op; 157299720Sarybchik uint32_t packet_id; 158299720Sarybchik struct pkt pkt; 159299720Sarybchik } samba_reply; 160299720Sarybchik 161299720Sarybchik char full_socket[256]; 162299720Sarybchik 163299720Sarybchik char *reply = NULL; 164299720Sarybchik uint32_t reply_len; 165299720Sarybchik 166299720Sarybchik ZERO(samba_pkt); 167299720Sarybchik samba_pkt.op = 0; /* Sign message */ 168299720Sarybchik /* This will be echoed into the reply - a different 169299720Sarybchik * impelementation might want multiple packets 170299720Sarybchik * awaiting signing */ 171299720Sarybchik 172293887Sarybchik samba_pkt.packet_id = 1; 173299720Sarybchik 174299720Sarybchik /* Swap the byte order back - it's actually little 175299720Sarybchik * endian on the wire, but it was read above as 176299720Sarybchik * network byte order */ 177299720Sarybchik samba_pkt.key_id_le = htonl(xkeyid); 178299720Sarybchik samba_pkt.pkt = *xpkt; 179299720Sarybchik 180299720Sarybchik snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket); 181299720Sarybchik 182299720Sarybchik fd = ux_socket_connect(full_socket); 183299720Sarybchik /* Only continue with this if we can talk to Samba */ 184299720Sarybchik if (fd != -1) { 185299720Sarybchik /* Send old packet to Samba, expect response */ 186299720Sarybchik /* Packet to Samba is quite simple: 187299720Sarybchik All values BIG endian except key ID as noted 188299720Sarybchik [packet size as BE] - 4 bytes 189299720Sarybchik [protocol version (0)] - 4 bytes 190299720Sarybchik [packet ID] - 4 bytes 191299720Sarybchik [operation (sign message=0)] - 4 bytes 192299720Sarybchik [key id] - LITTLE endian (as on wire) - 4 bytes 193299720Sarybchik [message to sign] - as marshalled, without signature 194299720Sarybchik */ 195299720Sarybchik 196299720Sarybchik if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) { 197299720Sarybchik /* Huh? could not talk to Samba... */ 198299720Sarybchik close(fd); 199299720Sarybchik return; 200299720Sarybchik } 201299720Sarybchik 202299720Sarybchik if (recv_packet(fd, &reply, &reply_len) != 0) { 203299720Sarybchik if (reply) { 204299720Sarybchik free(reply); 205299720Sarybchik } 206299720Sarybchik close(fd); 207299720Sarybchik return; 208299720Sarybchik } 209299720Sarybchik /* Return packet is also simple: 210299720Sarybchik [packet size] - network byte order - 4 bytes 211299720Sarybchik [protocol version (0)] network byte order - - 4 bytes 212299720Sarybchik [operation (signed success=3, failure=4)] network byte order - - 4 byte 213299720Sarybchik (optional) [signed message] - as provided before, with signature appended 214299720Sarybchik */ 215299720Sarybchik 216299720Sarybchik if (reply_len <= sizeof(samba_reply)) { 217299720Sarybchik memcpy(&samba_reply, reply, reply_len); 218299720Sarybchik if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) { 219299720Sarybchik sendlen = reply_len - offsetof(struct samba_key_out, pkt); 220299720Sarybchik xpkt = &samba_reply.pkt; 221299720Sarybchik sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen); 222299720Sarybchik#ifdef DEBUG 223299720Sarybchik if (debug) 224299720Sarybchik printf( 225299720Sarybchik "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n", 226299720Sarybchik current_time, ntoa(&rbufp->dstadr->sin), 227299720Sarybchik ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen); 228299720Sarybchik#endif 229299720Sarybchik } 230299720Sarybchik } 231299720Sarybchik 232299720Sarybchik if (reply) { 233299720Sarybchik free(reply); 234299720Sarybchik } 235299720Sarybchik close(fd); 236299720Sarybchik 237299720Sarybchik } 238299720Sarybchik} 239299720Sarybchik#endif 240299720Sarybchik