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 240