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 + (const 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 *buf = NULL; 117 return -1; 118 } 119 return 0; 120 } 121 122 void 123 send_via_ntp_signd( 124 struct recvbuf *rbufp, /* receive packet pointer */ 125 int xmode, 126 keyid_t xkeyid, 127 int flags, 128 struct pkt *xpkt 129 ) 130 { 131 132 /* We are here because it was detected that the client 133 * sent an all-zero signature, and we therefore know 134 * it's windows trying to talk to an AD server 135 * 136 * Because we don't want to dive into Samba's secrets 137 * database just to find the long-term kerberos key 138 * that is re-used as the NTP key, we instead hand the 139 * packet over to Samba to sign, and return to us. 140 * 141 * The signing method Samba will use is described by 142 * Microsoft in MS-SNTP, found here: 143 * http://msdn.microsoft.com/en-us/library/cc212930.aspx 144 */ 145 146 int fd, sendlen; 147 struct samba_key_in { 148 uint32_t version; 149 uint32_t op; 150 uint32_t packet_id; 151 uint32_t key_id_le; 152 struct pkt pkt; 153 } samba_pkt; 154 155 struct samba_key_out { 156 uint32_t version; 157 uint32_t op; 158 uint32_t packet_id; 159 struct pkt pkt; 160 } samba_reply; 161 162 char full_socket[256]; 163 164 char *reply = NULL; 165 uint32_t reply_len; 166 167 ZERO(samba_pkt); 168 samba_pkt.op = 0; /* Sign message */ 169 /* This will be echoed into the reply - a different 170 * impelementation might want multiple packets 171 * awaiting signing */ 172 173 samba_pkt.packet_id = 1; 174 175 /* Swap the byte order back - it's actually little 176 * endian on the wire, but it was read above as 177 * network byte order */ 178 samba_pkt.key_id_le = htonl(xkeyid); 179 samba_pkt.pkt = *xpkt; 180 181 snprintf(full_socket, sizeof(full_socket), "%s/socket", ntp_signd_socket); 182 183 fd = ux_socket_connect(full_socket); 184 /* Only continue with this if we can talk to Samba */ 185 if (fd != -1) { 186 /* Send old packet to Samba, expect response */ 187 /* Packet to Samba is quite simple: 188 All values BIG endian except key ID as noted 189 [packet size as BE] - 4 bytes 190 [protocol version (0)] - 4 bytes 191 [packet ID] - 4 bytes 192 [operation (sign message=0)] - 4 bytes 193 [key id] - LITTLE endian (as on wire) - 4 bytes 194 [message to sign] - as marshalled, without signature 195 */ 196 197 if (send_packet(fd, (char *)&samba_pkt, offsetof(struct samba_key_in, pkt) + LEN_PKT_NOMAC) != 0) { 198 /* Huh? could not talk to Samba... */ 199 close(fd); 200 return; 201 } 202 203 if (recv_packet(fd, &reply, &reply_len) != 0) { 204 if (reply) { 205 free(reply); 206 } 207 close(fd); 208 return; 209 } 210 /* Return packet is also simple: 211 [packet size] - network byte order - 4 bytes 212 [protocol version (0)] network byte order - - 4 bytes 213 [operation (signed success=3, failure=4)] network byte order - - 4 byte 214 (optional) [signed message] - as provided before, with signature appended 215 */ 216 217 if (reply_len <= sizeof(samba_reply)) { 218 memcpy(&samba_reply, reply, reply_len); 219 if (ntohl(samba_reply.op) == 3 && reply_len > offsetof(struct samba_key_out, pkt)) { 220 sendlen = reply_len - offsetof(struct samba_key_out, pkt); 221 xpkt = &samba_reply.pkt; 222 sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, xpkt, sendlen); 223 #ifdef DEBUG 224 if (debug) 225 printf( 226 "transmit ntp_signd packet: at %ld %s->%s mode %d keyid %08x len %d\n", 227 current_time, ntoa(&rbufp->dstadr->sin), 228 ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen); 229 #endif 230 } 231 } 232 233 if (reply) { 234 free(reply); 235 } 236 close(fd); 237 238 } 239 } 240 #endif 241