Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : NTP packet signing server
5 :
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
7 : Copyright (C) Andrew Tridgell 2005
8 : Copyright (C) Stefan Metzmacher 2005
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "samba/service_task.h"
26 : #include "samba/service.h"
27 : #include "samba/service_stream.h"
28 : #include "samba/process_model.h"
29 : #include "lib/stream/packet.h"
30 : #include "lib/tsocket/tsocket.h"
31 : #include "libcli/util/tstream.h"
32 : #include "librpc/gen_ndr/ndr_ntp_signd.h"
33 : #include "param/param.h"
34 : #include "dsdb/common/util.h"
35 : #include "dsdb/samdb/samdb.h"
36 : #include "auth/auth.h"
37 : #include "libcli/security/security.h"
38 : #include "libcli/ldap/ldap_ndr.h"
39 : #include <ldb.h>
40 : #include <ldb_errors.h>
41 : #include "system/network.h"
42 : #include "system/passwd.h"
43 :
44 : #include "lib/crypto/gnutls_helpers.h"
45 : #include <gnutls/gnutls.h>
46 : #include <gnutls/crypto.h>
47 :
48 : NTSTATUS server_service_ntp_signd_init(TALLOC_CTX *);
49 :
50 : /*
51 : top level context structure for the ntp_signd server
52 : */
53 : struct ntp_signd_server {
54 : struct task_server *task;
55 : struct ldb_context *samdb;
56 : };
57 :
58 : /*
59 : state of an open connection
60 : */
61 : struct ntp_signd_connection {
62 : /* stream connection we belong to */
63 : struct stream_connection *conn;
64 :
65 : /* the ntp_signd_server the connection belongs to */
66 : struct ntp_signd_server *ntp_signd;
67 :
68 : struct tstream_context *tstream;
69 :
70 : struct tevent_queue *send_queue;
71 : };
72 :
73 1 : static void ntp_signd_terminate_connection(struct ntp_signd_connection *ntp_signd_conn, const char *reason)
74 : {
75 1 : stream_terminate_connection(ntp_signd_conn->conn, reason);
76 1 : }
77 :
78 0 : static NTSTATUS signing_failure(struct ntp_signd_connection *ntp_signdconn,
79 : TALLOC_CTX *mem_ctx,
80 : DATA_BLOB *output,
81 : uint32_t packet_id)
82 : {
83 0 : struct signed_reply signed_reply;
84 0 : enum ndr_err_code ndr_err;
85 :
86 0 : signed_reply.op = SIGNING_FAILURE;
87 0 : signed_reply.packet_id = packet_id;
88 0 : signed_reply.signed_packet = data_blob(NULL, 0);
89 :
90 0 : ndr_err = ndr_push_struct_blob(output, mem_ctx, &signed_reply,
91 : (ndr_push_flags_fn_t)ndr_push_signed_reply);
92 :
93 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
94 0 : DEBUG(1,("failed to push ntp error reply\n"));
95 0 : return ndr_map_error2ntstatus(ndr_err);
96 : }
97 :
98 0 : return NT_STATUS_OK;
99 : }
100 :
101 : /*
102 : receive a full packet on a NTP_SIGND connection
103 : */
104 1 : static NTSTATUS ntp_signd_process(struct ntp_signd_connection *ntp_signd_conn,
105 : TALLOC_CTX *mem_ctx,
106 : DATA_BLOB *input,
107 : DATA_BLOB *output)
108 : {
109 0 : const struct dom_sid *domain_sid;
110 0 : struct dom_sid *sid;
111 0 : struct sign_request sign_request;
112 0 : struct signed_reply signed_reply;
113 0 : enum ndr_err_code ndr_err;
114 0 : struct ldb_result *res;
115 0 : static const char *attrs[] = {
116 : "unicodePwd",
117 : "userAccountControl",
118 : "cn",
119 : /* Required for Group Managed Service Accounts. */
120 : "msDS-ManagedPasswordId",
121 : "msDS-ManagedPasswordInterval",
122 : "objectClass",
123 : "objectSid",
124 : "whenCreated",
125 : NULL};
126 1 : gnutls_hash_hd_t hash_hnd = NULL;
127 0 : struct samr_Password *nt_hash;
128 0 : uint32_t user_account_control;
129 0 : struct dom_sid_buf buf;
130 0 : int ret;
131 :
132 1 : ndr_err = ndr_pull_struct_blob_all(input, mem_ctx,
133 : &sign_request,
134 : (ndr_pull_flags_fn_t)ndr_pull_sign_request);
135 :
136 1 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137 0 : DEBUG(1,("failed to parse ntp signing request\n"));
138 0 : dump_data(1, input->data, input->length);
139 0 : return ndr_map_error2ntstatus(ndr_err);
140 : }
141 :
142 : /* We need to implement 'check signature' and 'request server
143 : * to sign' operations at some point */
144 1 : if (sign_request.op != SIGN_TO_CLIENT) {
145 0 : return signing_failure(ntp_signd_conn,
146 : mem_ctx,
147 : output,
148 0 : sign_request.packet_id);
149 : }
150 :
151 : /* We need to implement 'check signature' and 'request server
152 : * to sign' operations at some point */
153 1 : if (sign_request.version != NTP_SIGND_PROTOCOL_VERSION_0) {
154 0 : return signing_failure(ntp_signd_conn,
155 : mem_ctx,
156 : output,
157 0 : sign_request.packet_id);
158 : }
159 :
160 1 : domain_sid = samdb_domain_sid(ntp_signd_conn->ntp_signd->samdb);
161 1 : if (domain_sid == NULL) {
162 0 : return signing_failure(ntp_signd_conn,
163 : mem_ctx,
164 : output,
165 0 : sign_request.packet_id);
166 : }
167 :
168 : /* The top bit is a 'key selector' */
169 1 : sid = dom_sid_add_rid(mem_ctx, domain_sid,
170 1 : sign_request.key_id & 0x7FFFFFFF);
171 1 : if (sid == NULL) {
172 0 : talloc_free(mem_ctx);
173 0 : return signing_failure(ntp_signd_conn,
174 : mem_ctx,
175 : output,
176 0 : sign_request.packet_id);
177 : }
178 :
179 2 : ret = dsdb_search(ntp_signd_conn->ntp_signd->samdb, mem_ctx,
180 : &res,
181 1 : ldb_get_default_basedn(ntp_signd_conn->ntp_signd->samdb),
182 : LDB_SCOPE_SUBTREE,
183 : attrs,
184 : DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
185 : "(&(objectSid=%s)(objectClass=user))",
186 : ldap_encode_ndr_dom_sid(mem_ctx, sid));
187 1 : if (ret != LDB_SUCCESS) {
188 0 : DEBUG(2, ("Failed to search for SID %s in SAM for NTP signing: "
189 : "%s\n",
190 : dom_sid_str_buf(sid, &buf),
191 : ldb_errstring(ntp_signd_conn->ntp_signd->samdb)));
192 0 : return signing_failure(ntp_signd_conn,
193 : mem_ctx,
194 : output,
195 0 : sign_request.packet_id);
196 : }
197 :
198 1 : if (res->count == 0) {
199 0 : DEBUG(2, ("Failed to find SID %s in SAM for NTP signing\n",
200 : dom_sid_str_buf(sid, &buf)));
201 0 : return signing_failure(ntp_signd_conn,
202 : mem_ctx,
203 : output,
204 0 : sign_request.packet_id);
205 1 : } else if (res->count != 1) {
206 0 : DEBUG(1, ("Found SID %s %u times in SAM for NTP signing\n",
207 : dom_sid_str_buf(sid, &buf),
208 : res->count));
209 0 : return signing_failure(ntp_signd_conn,
210 : mem_ctx,
211 : output,
212 0 : sign_request.packet_id);
213 : }
214 :
215 1 : user_account_control = ldb_msg_find_attr_as_uint(res->msgs[0],
216 : "userAccountControl",
217 : 0);
218 :
219 1 : if (user_account_control & UF_ACCOUNTDISABLE) {
220 0 : DEBUG(1, ("Account %s for SID [%s] is disabled\n",
221 : ldb_dn_get_linearized(res->msgs[0]->dn),
222 : dom_sid_str_buf(sid, &buf)));
223 0 : return NT_STATUS_ACCESS_DENIED;
224 : }
225 :
226 1 : if (!(user_account_control & (UF_INTERDOMAIN_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT))) {
227 0 : DEBUG(1, ("Account %s for SID [%s] is not a trust account\n",
228 : ldb_dn_get_linearized(res->msgs[0]->dn),
229 : dom_sid_str_buf(sid, &buf)));
230 0 : return NT_STATUS_ACCESS_DENIED;
231 : }
232 :
233 1 : nt_hash = samdb_result_hash(mem_ctx, res->msgs[0], "unicodePwd");
234 1 : if (!nt_hash) {
235 0 : DEBUG(1, ("No unicodePwd found on record of SID %s "
236 : "for NTP signing\n",
237 : dom_sid_str_buf(sid, &buf)));
238 0 : return signing_failure(ntp_signd_conn,
239 : mem_ctx,
240 : output,
241 0 : sign_request.packet_id);
242 : }
243 :
244 : /* Generate the reply packet */
245 1 : signed_reply.packet_id = sign_request.packet_id;
246 1 : signed_reply.op = SIGNING_SUCCESS;
247 1 : signed_reply.signed_packet = data_blob_talloc(mem_ctx,
248 : NULL,
249 : sign_request.packet_to_sign.length + 20);
250 :
251 1 : if (!signed_reply.signed_packet.data) {
252 0 : return signing_failure(ntp_signd_conn,
253 : mem_ctx,
254 : output,
255 0 : sign_request.packet_id);
256 : }
257 :
258 1 : memcpy(signed_reply.signed_packet.data, sign_request.packet_to_sign.data, sign_request.packet_to_sign.length);
259 1 : SIVAL(signed_reply.signed_packet.data, sign_request.packet_to_sign.length, sign_request.key_id);
260 :
261 : /* Sign the NTP response with the unicodePwd */
262 1 : ret = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
263 1 : if (ret < 0) {
264 0 : return gnutls_error_to_ntstatus(ret, NT_STATUS_HASH_NOT_SUPPORTED);
265 : }
266 :
267 1 : ret = gnutls_hash(hash_hnd,
268 1 : nt_hash->hash,
269 : sizeof(nt_hash->hash));
270 1 : if (ret < 0) {
271 0 : gnutls_hash_deinit(hash_hnd, NULL);
272 0 : return gnutls_error_to_ntstatus(ret, NT_STATUS_HASH_NOT_SUPPORTED);
273 : }
274 1 : ret = gnutls_hash(hash_hnd,
275 1 : sign_request.packet_to_sign.data,
276 : sign_request.packet_to_sign.length);
277 1 : if (ret < 0) {
278 0 : gnutls_hash_deinit(hash_hnd, NULL);
279 0 : return gnutls_error_to_ntstatus(ret, NT_STATUS_HASH_NOT_SUPPORTED);
280 : }
281 :
282 1 : gnutls_hash_deinit(hash_hnd,
283 1 : signed_reply.signed_packet.data +
284 1 : sign_request.packet_to_sign.length + 4);
285 :
286 : /* Place it into the packet for the wire */
287 1 : ndr_err = ndr_push_struct_blob(output, mem_ctx, &signed_reply,
288 : (ndr_push_flags_fn_t)ndr_push_signed_reply);
289 :
290 1 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
291 0 : DEBUG(1,("failed to push ntp error reply\n"));
292 0 : return ndr_map_error2ntstatus(ndr_err);
293 : }
294 :
295 1 : return NT_STATUS_OK;
296 : }
297 :
298 : /*
299 : called on a tcp recv
300 : */
301 0 : static void ntp_signd_recv(struct stream_connection *conn, uint16_t flags)
302 : {
303 0 : struct ntp_signd_connection *ntp_signd_conn = talloc_get_type(conn->private_data,
304 : struct ntp_signd_connection);
305 0 : ntp_signd_terminate_connection(ntp_signd_conn,
306 : "ntp_signd_recv: called");
307 0 : }
308 :
309 : /*
310 : called when we can write to a connection
311 : */
312 0 : static void ntp_signd_send(struct stream_connection *conn, uint16_t flags)
313 : {
314 0 : struct ntp_signd_connection *ntp_signd_conn = talloc_get_type(conn->private_data,
315 : struct ntp_signd_connection);
316 : /* this should never be triggered! */
317 0 : ntp_signd_terminate_connection(ntp_signd_conn,
318 : "ntp_signd_send: called");
319 0 : }
320 :
321 : struct ntp_signd_call {
322 : struct ntp_signd_connection *ntp_signd_conn;
323 : DATA_BLOB in;
324 : DATA_BLOB out;
325 : uint8_t out_hdr[4];
326 : struct iovec out_iov[2];
327 : };
328 :
329 : static void ntp_signd_call_writev_done(struct tevent_req *subreq);
330 :
331 2 : static void ntp_signd_call_loop(struct tevent_req *subreq)
332 : {
333 2 : struct ntp_signd_connection *ntp_signd_conn = tevent_req_callback_data(subreq,
334 : struct ntp_signd_connection);
335 0 : struct ntp_signd_call *call;
336 0 : NTSTATUS status;
337 :
338 2 : call = talloc(ntp_signd_conn, struct ntp_signd_call);
339 2 : if (call == NULL) {
340 0 : ntp_signd_terminate_connection(ntp_signd_conn,
341 : "ntp_signd_call_loop: "
342 : "no memory for ntp_signd_call");
343 1 : return;
344 : }
345 2 : call->ntp_signd_conn = ntp_signd_conn;
346 :
347 2 : status = tstream_read_pdu_blob_recv(subreq,
348 : call,
349 : &call->in);
350 2 : TALLOC_FREE(subreq);
351 2 : if (!NT_STATUS_IS_OK(status)) {
352 0 : const char *reason;
353 :
354 1 : reason = talloc_asprintf(call, "ntp_signd_call_loop: "
355 : "tstream_read_pdu_blob_recv() - %s",
356 : nt_errstr(status));
357 1 : if (reason == NULL) {
358 0 : reason = nt_errstr(status);
359 : }
360 :
361 1 : ntp_signd_terminate_connection(ntp_signd_conn, reason);
362 1 : return;
363 : }
364 :
365 1 : DEBUG(10,("Received NTP TCP packet of length %lu from %s\n",
366 : (long) call->in.length,
367 : tsocket_address_string(ntp_signd_conn->conn->remote_address, call)));
368 :
369 : /* skip length header */
370 1 : call->in.data +=4;
371 1 : call->in.length -= 4;
372 :
373 1 : status = ntp_signd_process(ntp_signd_conn,
374 : call,
375 : &call->in,
376 : &call->out);
377 1 : if (! NT_STATUS_IS_OK(status)) {
378 0 : const char *reason;
379 :
380 0 : reason = talloc_asprintf(call, "ntp_signd_process failed: %s",
381 : nt_errstr(status));
382 0 : if (reason == NULL) {
383 0 : reason = nt_errstr(status);
384 : }
385 :
386 0 : ntp_signd_terminate_connection(ntp_signd_conn, reason);
387 0 : return;
388 : }
389 :
390 : /* First add the length of the out buffer */
391 1 : RSIVAL(call->out_hdr, 0, call->out.length);
392 1 : call->out_iov[0].iov_base = (char *) call->out_hdr;
393 1 : call->out_iov[0].iov_len = 4;
394 :
395 1 : call->out_iov[1].iov_base = (char *) call->out.data;
396 1 : call->out_iov[1].iov_len = call->out.length;
397 :
398 1 : subreq = tstream_writev_queue_send(call,
399 1 : ntp_signd_conn->conn->event.ctx,
400 : ntp_signd_conn->tstream,
401 : ntp_signd_conn->send_queue,
402 1 : call->out_iov, 2);
403 1 : if (subreq == NULL) {
404 0 : ntp_signd_terminate_connection(ntp_signd_conn, "ntp_signd_call_loop: "
405 : "no memory for tstream_writev_queue_send");
406 0 : return;
407 : }
408 :
409 1 : tevent_req_set_callback(subreq, ntp_signd_call_writev_done, call);
410 :
411 : /*
412 : * The NTP tcp pdu's has the length as 4 byte (initial_read_size),
413 : * tstream_full_request_u32 provides the pdu length then.
414 : */
415 1 : subreq = tstream_read_pdu_blob_send(ntp_signd_conn,
416 1 : ntp_signd_conn->conn->event.ctx,
417 : ntp_signd_conn->tstream,
418 : 4, /* initial_read_size */
419 : tstream_full_request_u32,
420 : ntp_signd_conn);
421 1 : if (subreq == NULL) {
422 0 : ntp_signd_terminate_connection(ntp_signd_conn, "ntp_signd_call_loop: "
423 : "no memory for tstream_read_pdu_blob_send");
424 0 : return;
425 : }
426 1 : tevent_req_set_callback(subreq, ntp_signd_call_loop, ntp_signd_conn);
427 : }
428 :
429 1 : static void ntp_signd_call_writev_done(struct tevent_req *subreq)
430 : {
431 1 : struct ntp_signd_call *call = tevent_req_callback_data(subreq,
432 : struct ntp_signd_call);
433 0 : int sys_errno;
434 0 : int rc;
435 :
436 1 : rc = tstream_writev_queue_recv(subreq, &sys_errno);
437 1 : TALLOC_FREE(subreq);
438 1 : if (rc == -1) {
439 0 : const char *reason;
440 :
441 0 : reason = talloc_asprintf(call, "ntp_signd_call_writev_done: "
442 : "tstream_writev_queue_recv() - %d:%s",
443 : sys_errno, strerror(sys_errno));
444 0 : if (!reason) {
445 0 : reason = "ntp_signd_call_writev_done: "
446 : "tstream_writev_queue_recv() failed";
447 : }
448 :
449 0 : ntp_signd_terminate_connection(call->ntp_signd_conn, reason);
450 0 : return;
451 : }
452 :
453 : /* We don't care about errors */
454 :
455 1 : talloc_free(call);
456 : }
457 :
458 : /*
459 : called when we get a new connection
460 : */
461 1 : static void ntp_signd_accept(struct stream_connection *conn)
462 : {
463 1 : struct ntp_signd_server *ntp_signd = talloc_get_type(conn->private_data,
464 : struct ntp_signd_server);
465 0 : struct ntp_signd_connection *ntp_signd_conn;
466 0 : struct tevent_req *subreq;
467 0 : int rc;
468 :
469 1 : ntp_signd_conn = talloc_zero(conn, struct ntp_signd_connection);
470 1 : if (ntp_signd_conn == NULL) {
471 0 : stream_terminate_connection(conn,
472 : "ntp_signd_accept: out of memory");
473 0 : return;
474 : }
475 :
476 1 : ntp_signd_conn->send_queue = tevent_queue_create(conn,
477 : "ntp_signd_accept");
478 1 : if (ntp_signd_conn->send_queue == NULL) {
479 0 : stream_terminate_connection(conn,
480 : "ntp_signd_accept: out of memory");
481 0 : return;
482 : }
483 :
484 1 : TALLOC_FREE(conn->event.fde);
485 :
486 1 : rc = tstream_bsd_existing_socket(ntp_signd_conn,
487 : socket_get_fd(conn->socket),
488 : &ntp_signd_conn->tstream);
489 1 : if (rc < 0) {
490 0 : stream_terminate_connection(conn,
491 : "ntp_signd_accept: out of memory");
492 0 : return;
493 : }
494 : /* as server we want to fail early */
495 1 : tstream_bsd_fail_readv_first_error(ntp_signd_conn->tstream, true);
496 :
497 1 : ntp_signd_conn->conn = conn;
498 1 : ntp_signd_conn->ntp_signd = ntp_signd;
499 1 : conn->private_data = ntp_signd_conn;
500 :
501 : /*
502 : * The NTP tcp pdu's has the length as 4 byte (initial_read_size),
503 : * tstream_full_request_u32 provides the pdu length then.
504 : */
505 1 : subreq = tstream_read_pdu_blob_send(ntp_signd_conn,
506 1 : ntp_signd_conn->conn->event.ctx,
507 : ntp_signd_conn->tstream,
508 : 4, /* initial_read_size */
509 : tstream_full_request_u32,
510 : ntp_signd_conn);
511 1 : if (subreq == NULL) {
512 0 : ntp_signd_terminate_connection(ntp_signd_conn,
513 : "ntp_signd_accept: "
514 : "no memory for tstream_read_pdu_blob_send");
515 0 : return;
516 : }
517 1 : tevent_req_set_callback(subreq, ntp_signd_call_loop, ntp_signd_conn);
518 : }
519 :
520 : static const struct stream_server_ops ntp_signd_stream_ops = {
521 : .name = "ntp_signd",
522 : .accept_connection = ntp_signd_accept,
523 : .recv_handler = ntp_signd_recv,
524 : .send_handler = ntp_signd_send
525 : };
526 :
527 : /*
528 : startup the ntp_signd task
529 : */
530 65 : static NTSTATUS ntp_signd_task_init(struct task_server *task)
531 : {
532 2 : struct ntp_signd_server *ntp_signd;
533 2 : NTSTATUS status;
534 :
535 2 : const char *address;
536 :
537 65 : if (!directory_create_or_exist_strict(lpcfg_ntp_signd_socket_directory(task->lp_ctx), geteuid(), 0750)) {
538 0 : char *error = talloc_asprintf(task, "Cannot create NTP signd pipe directory: %s",
539 : lpcfg_ntp_signd_socket_directory(task->lp_ctx));
540 0 : task_server_terminate(task,
541 : error, true);
542 0 : return NT_STATUS_UNSUCCESSFUL;
543 : }
544 :
545 65 : task_server_set_title(task, "task[ntp_signd]");
546 :
547 65 : ntp_signd = talloc(task, struct ntp_signd_server);
548 65 : if (ntp_signd == NULL) {
549 0 : task_server_terminate(task, "ntp_signd: out of memory", true);
550 0 : return NT_STATUS_NO_MEMORY;
551 : }
552 :
553 65 : ntp_signd->task = task;
554 :
555 : /* Must be system to get at the password hashes */
556 65 : ntp_signd->samdb = samdb_connect(ntp_signd,
557 : task->event_ctx,
558 : task->lp_ctx,
559 : system_session(task->lp_ctx),
560 : NULL,
561 : 0);
562 65 : if (ntp_signd->samdb == NULL) {
563 0 : task_server_terminate(task, "ntp_signd failed to open samdb", true);
564 0 : return NT_STATUS_UNSUCCESSFUL;
565 : }
566 :
567 65 : address = talloc_asprintf(ntp_signd, "%s/socket", lpcfg_ntp_signd_socket_directory(task->lp_ctx));
568 65 : if (address == NULL) {
569 0 : task_server_terminate(
570 : task, "ntp_signd out of memory in talloc_asprintf()", true);
571 0 : return NT_STATUS_NO_MEMORY;
572 : }
573 :
574 130 : status = stream_setup_socket(ntp_signd->task,
575 63 : ntp_signd->task->event_ctx,
576 65 : ntp_signd->task->lp_ctx,
577 : task->model_ops,
578 : &ntp_signd_stream_ops,
579 : "unix", address, NULL,
580 63 : lpcfg_socket_options(ntp_signd->task->lp_ctx),
581 : ntp_signd,
582 65 : ntp_signd->task->process_context);
583 65 : if (!NT_STATUS_IS_OK(status)) {
584 0 : DEBUG(0,("Failed to bind to %s - %s\n",
585 : address, nt_errstr(status)));
586 0 : return status;
587 : }
588 :
589 65 : return NT_STATUS_OK;
590 :
591 : }
592 :
593 :
594 : /* called at smbd startup - register ourselves as a server service */
595 66 : NTSTATUS server_service_ntp_signd_init(TALLOC_CTX *ctx)
596 : {
597 3 : static const struct service_details details = {
598 : .inhibit_fork_on_accept = true,
599 : .inhibit_pre_fork = true,
600 : .task_init = ntp_signd_task_init,
601 : .post_fork = NULL
602 : };
603 66 : return register_server_service(ctx, "ntp_signd", &details);
604 : }
|