2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2016
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **********************************************************************
22 =======================================================================
24 Support for MS-SNTP authentication in Samba (ntp_signd)
35 #include "ntp_signd.h"
40 /* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
42 #define SIGND_VERSION 0
46 ASK_SERVER_TO_SIGN
= 1,
47 CHECK_SERVER_SIGNATURE
= 2,
59 NTP_Packet packet_to_sign
;
67 NTP_Packet signed_packet
;
71 NTP_Remote_Address remote_addr
;
72 NTP_Local_Address local_addr
;
77 struct timespec request_ts
;
79 SigndResponse response
;
82 /* As the communication with ntp_signd is asynchronous, incoming packets are
83 saved in a queue in order to avoid loss when they come in bursts */
85 #define MAX_QUEUE_LENGTH 16U
86 #define NEXT_QUEUE_INDEX(index) (((index) + 1) % MAX_QUEUE_LENGTH)
87 #define IS_QUEUE_EMPTY() (queue_head == queue_tail)
89 /* Fixed-size array of SignInstance */
90 static ARR_Instance queue
;
91 static unsigned int queue_head
;
92 static unsigned int queue_tail
;
94 #define INVALID_SOCK_FD (-6)
96 /* Unix domain socket connected to ntp_signd */
99 /* Flag indicating if the MS-SNTP authentication is enabled */
102 /* ================================================== */
104 static void read_write_socket(int sock_fd
, int event
, void *anything
);
106 /* ================================================== */
111 SCH_RemoveFileHandler(sock_fd
);
112 SCK_CloseSocket(sock_fd
);
113 sock_fd
= INVALID_SOCK_FD
;
115 /* Empty the queue */
116 queue_head
= queue_tail
= 0;
119 /* ================================================== */
126 if (sock_fd
!= INVALID_SOCK_FD
)
129 if (snprintf(path
, sizeof (path
), "%s/socket", CNF_GetNtpSigndSocket()) >= sizeof (path
)) {
130 DEBUG_LOG("signd socket path too long");
134 sock_fd
= SCK_OpenUnixStreamSocket(path
, NULL
, 0);
136 sock_fd
= INVALID_SOCK_FD
;
140 SCH_AddFileHandler(sock_fd
, SCH_FILE_INPUT
, read_write_socket
, NULL
);
145 /* ================================================== */
148 process_response(SignInstance
*inst
)
153 if (ntohs(inst
->request
.packet_id
) != ntohl(inst
->response
.packet_id
)) {
154 DEBUG_LOG("Invalid response ID");
158 if (ntohl(inst
->response
.op
) != SIGNING_SUCCESS
) {
159 DEBUG_LOG("Signing failed");
163 /* Check if the file descriptor is still valid */
164 if (!NIO_IsServerSocket(inst
->local_addr
.sock_fd
)) {
165 DEBUG_LOG("Invalid NTP socket");
169 SCH_GetLastEventTime(NULL
, NULL
, &ts
);
170 delay
= UTI_DiffTimespecsToDouble(&ts
, &inst
->request_ts
);
172 DEBUG_LOG("Signing succeeded (delay %f)", delay
);
174 /* Send the signed NTP packet */
175 NIO_SendPacket(&inst
->response
.signed_packet
, &inst
->remote_addr
, &inst
->local_addr
,
176 ntohl(inst
->response
.length
) + sizeof (inst
->response
.length
) -
177 offsetof(SigndResponse
, signed_packet
), 0);
180 /* ================================================== */
183 read_write_socket(int sock_fd
, int event
, void *anything
)
186 uint32_t response_length
;
189 inst
= ARR_GetElement(queue
, queue_head
);
191 if (event
== SCH_FILE_OUTPUT
) {
192 assert(!IS_QUEUE_EMPTY());
193 assert(inst
->sent
< inst
->request_length
);
196 SCH_GetLastEventTime(NULL
, NULL
, &inst
->request_ts
);
198 s
= SCK_Send(sock_fd
, (char *)&inst
->request
+ inst
->sent
,
199 inst
->request_length
- inst
->sent
, 0);
208 /* Try again later if the request is not complete yet */
209 if (inst
->sent
< inst
->request_length
)
212 /* Disable output and wait for a response */
213 SCH_SetFileHandlerEvent(sock_fd
, SCH_FILE_OUTPUT
, 0);
216 if (event
== SCH_FILE_INPUT
) {
217 if (IS_QUEUE_EMPTY()) {
218 DEBUG_LOG("Unexpected signd response");
223 assert(inst
->received
< sizeof (inst
->response
));
224 s
= SCK_Receive(sock_fd
, (char *)&inst
->response
+ inst
->received
,
225 sizeof (inst
->response
) - inst
->received
, 0);
234 if (inst
->received
< sizeof (inst
->response
.length
))
237 response_length
= ntohl(inst
->response
.length
) + sizeof (inst
->response
.length
);
239 if (response_length
< offsetof(SigndResponse
, signed_packet
) ||
240 response_length
> sizeof (SigndResponse
)) {
241 DEBUG_LOG("Invalid response length");
246 /* Wait for more data if not complete yet */
247 if (inst
->received
< response_length
)
250 process_response(inst
);
252 /* Move the head and enable output for the next packet */
253 queue_head
= NEXT_QUEUE_INDEX(queue_head
);
254 if (!IS_QUEUE_EMPTY())
255 SCH_SetFileHandlerEvent(sock_fd
, SCH_FILE_OUTPUT
, 1);
259 /* ================================================== */
264 sock_fd
= INVALID_SOCK_FD
;
265 enabled
= CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
270 queue
= ARR_CreateInstance(sizeof (SignInstance
));
271 ARR_SetSize(queue
, MAX_QUEUE_LENGTH
);
272 queue_head
= queue_tail
= 0;
274 LOG(LOGS_INFO
, "MS-SNTP authentication enabled");
277 /* ================================================== */
284 if (sock_fd
!= INVALID_SOCK_FD
)
286 ARR_DestroyInstance(queue
);
289 /* ================================================== */
292 NSD_SignAndSendPacket(uint32_t key_id
, NTP_Packet
*packet
, NTP_PacketInfo
*info
,
293 NTP_Remote_Address
*remote_addr
, NTP_Local_Address
*local_addr
)
298 DEBUG_LOG("signd disabled");
302 if (queue_head
== NEXT_QUEUE_INDEX(queue_tail
)) {
303 DEBUG_LOG("signd queue full");
307 if (info
->length
!= NTP_HEADER_LENGTH
) {
308 DEBUG_LOG("Invalid packet length");
315 inst
= ARR_GetElement(queue
, queue_tail
);
316 inst
->remote_addr
= *remote_addr
;
317 inst
->local_addr
= *local_addr
;
320 inst
->request_length
= offsetof(SigndRequest
, packet_to_sign
) + info
->length
;
322 /* The length field doesn't include itself */
323 inst
->request
.length
= htonl(inst
->request_length
- sizeof (inst
->request
.length
));
324 inst
->request
.version
= htonl(SIGND_VERSION
);
325 inst
->request
.op
= htonl(SIGN_TO_CLIENT
);
326 inst
->request
.packet_id
= htons(queue_tail
);
327 inst
->request
._pad
= 0;
328 inst
->request
.key_id
= htonl(key_id
);
330 memcpy(&inst
->request
.packet_to_sign
, packet
, info
->length
);
332 /* Enable output if there was no pending request */
333 if (IS_QUEUE_EMPTY())
334 SCH_SetFileHandlerEvent(sock_fd
, SCH_FILE_OUTPUT
, 1);
336 queue_tail
= NEXT_QUEUE_INDEX(queue_tail
);
338 DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head
, queue_tail
);