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