ntp_signd.c revision 1.1.1.1
1/* $NetBSD: ntp_signd.c,v 1.1.1.1 2009/12/13 16:55:41 kardel Exp $ */ 2 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 10 11#ifdef HAVE_NTP_SIGND 12 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" 19 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 */ 26 27#include <sys/un.h> 28 29/* socket routines by tridge - from junkcode.samba.org */ 30 31/* 32 connect to a unix domain socket 33*/ 34static int 35ux_socket_connect(const char *name) 36{ 37 int fd; 38 struct sockaddr_un addr; 39 if (!name) { 40 return -1; 41 } 42 43 memset(&addr, 0, sizeof(addr)); 44 addr.sun_family = AF_UNIX; 45 strncpy(addr.sun_path, name, sizeof(addr.sun_path)); 46 47 fd = socket(AF_UNIX, SOCK_STREAM, 0); 48 if (fd == -1) { 49 return -1; 50 } 51 52 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 53 close(fd); 54 return -1; 55 } 56 57 return fd; 58} 59 60 61/* 62 keep writing until its all sent 63*/ 64static int 65write_all(int fd, const void *buf, size_t len) 66{ 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; 74 } 75 return total; 76} 77 78/* 79 keep reading until its all read 80*/ 81static int 82read_all(int fd, void *buf, size_t len) 83{ 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; 91 } 92 return total; 93} 94 95/* 96 send a packet in length prefix format 97*/ 98static int 99send_packet(int fd, const char *buf, uint32_t len) 100{ 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; 105} 106 107/* 108 receive a packet in length prefix format 109*/ 110static int 111recv_packet(int fd, char **buf, uint32_t *len) 112{ 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; 119 } 120 return 0; 121} 122 123void 124send_via_ntp_signd( 125 struct recvbuf *rbufp, /* receive packet pointer */ 126 int xmode, 127 keyid_t xkeyid, 128 int flags, 129 struct pkt *xpkt 130 ) 131{ 132 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 136 * 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. 141 * 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 145 */ 146 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; 155 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; 162 163 char full_socket[256]; 164 165 char *reply = NULL; 166 uint32_t reply_len; 167 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 */ 173 174 samba_pkt.packet_id = 1; 175 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; 181 182 snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket); 183 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 196 */ 197 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; 202 } 203 204 if (recv_packet(fd, &reply, &reply_len) != 0) { 205 if (reply) { 206 free(reply); 207 } 208 close(fd); 209 return; 210 } 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 216 */ 217 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 231 } 232 } 233 234 if (reply) { 235 free(reply); 236 } 237 close(fd); 238 239 } 240} 241#endif 242