Start an 'NTP signing server' in Samba4.
[kai/samba.git] / source4 / ntp_signd / ntp_signd.c
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 "smbd/service_task.h"
26 #include "smbd/service.h"
27 #include "smbd/service_stream.h"
28 #include "smbd/process_model.h"
29 #include "lib/stream/packet.h"
30 #include "librpc/gen_ndr/ntp_signd.h"
31 #include "param/param.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/auth.h"
34
35 /*
36   top level context structure for the ntp_signd server
37 */
38 struct ntp_signd_server {
39         struct task_server *task;
40         struct ldb_context *samdb;
41 };
42
43 /*
44   state of an open connection
45 */
46 struct ntp_signd_connection {
47         /* stream connection we belong to */
48         struct stream_connection *conn;
49
50         /* the ntp_signd_server the connection belongs to */
51         struct ntp_signd_server *ntp_signd;
52
53         struct packet_context *packet;
54 };
55
56 static void ntp_signd_terminate_connection(struct ntp_signd_connection *ntp_signdconn, const char *reason)
57 {
58         stream_terminate_connection(ntp_signdconn->conn, reason);
59 }
60
61 /*
62   receive a full packet on a NTP_SIGND connection
63 */
64 static NTSTATUS ntp_signd_recv(void *private, DATA_BLOB blob)
65 {
66         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(private, 
67                                                              struct ntp_signd_connection);
68         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
69         TALLOC_CTX *tmp_ctx = talloc_new(ntp_signdconn);
70         DATA_BLOB input, reply;
71         const struct dom_sid *domain_sid;
72         struct dom_sid *sid;
73         struct sign_request sign_request;
74         enum ndr_err_code ndr_err;
75         struct ldb_result *res;
76         const char *attrs[] = { "unicodePwd", NULL };
77
78         talloc_steal(tmp_ctx, blob.data);
79
80         input = data_blob_const(blob.data + 4, blob.length - 4); 
81
82         ndr_err = ndr_pull_struct_blob_all(input, tmp_ctx, 
83                                            iconv_convenience,
84                                            &sign_request,
85                                            (ndr_pull_flags_fn_t)ndr_pull_sign_request);
86
87         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
88                 DEBUG(1,("failed to parse ntp signing request\n"));
89                 dump_data(1, input.data, input.length);
90                 return ndr_map_error2ntstatus(ndr_err);
91         }
92
93         domain_sid = samdb_domain_sid(ntp_signdconn->ntp_signd->samdb);
94         if (!domain_sid) {
95                 return NT_STATUS_INVALID_PARAMETER;
96         }
97         
98         sid = dom_sid_add_rid(tmp_ctx, domain_sid, sign_request.key_id & 0x7FFFFFFF);
99         if (!sid) {
100                 return NT_STATUS_NO_MEMORY;
101         }
102
103         /* Sign packet */
104         ret = ldb_search_exp_format(ntp_signdconn->ntp_signd->samdb, tmp_ctx,
105                                     &res, samdb_base_dn(ntp_signdconn->ntp_signd->samdb),
106                                     LDB_SCOPE_SUBTREE, attrs, "(&(objectSid=%s)(objectClass=computer))");
107         if (ret != LDB_SUCCESS) {
108                 return NT_STATUS_UNSUCCESSFUL;
109         }
110
111         if (res->count != 1) {
112                 return NT_STATUS_NO_SUCH_USER;
113         }
114
115         /* Sign the NTP response with the unicodePwd */
116
117         /* Place it into the packet for the wire */
118
119         blob = data_blob_talloc(ntp_signdconn, NULL, reply.length + 4);
120         if (!blob.data) {
121                 talloc_free(tmp_ctx);
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         RSIVAL(blob.data, 0, reply.length);
126         memcpy(blob.data + 4, reply.data, reply.length);        
127
128         status = packet_send(ntp_signdconn->packet, blob);
129
130         /* the call isn't needed any more */
131         talloc_free(tmp_ctx);
132         return status;
133 }
134
135 /*
136   receive some data on a NTP_SIGND connection
137 */
138 static void ntp_signd_recv_handler(struct stream_connection *conn, uint16_t flags)
139 {
140         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(conn->private, 
141                                                              struct ntp_signd_connection);
142         packet_recv(ntp_signdconn->packet);
143 }
144
145 /*
146   called on a tcp recv error
147 */
148 static void ntp_signd_recv_error(void *private, NTSTATUS status)
149 {
150         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(private, struct ntp_signd_connection);
151         ntp_signd_terminate_connection(ntp_signdconn, nt_errstr(status));
152 }
153
154 /*
155   called when we can write to a connection
156 */
157 static void ntp_signd_send(struct stream_connection *conn, uint16_t flags)
158 {
159         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(conn->private, 
160                                                              struct ntp_signd_connection);
161         packet_queue_run(ntp_signdconn->packet);
162 }
163
164 /*
165   called when we get a new connection
166 */
167 static void ntp_signd_accept(struct stream_connection *conn)
168 {
169         struct ntp_signd_server *ntp_signd = talloc_get_type(conn->private, struct ntp_signd_server);
170         struct ntp_signd_connection *ntp_signdconn;
171
172         ntp_signdconn = talloc_zero(conn, struct ntp_signd_connection);
173         if (!ntp_signdconn) {
174                 stream_terminate_connection(conn, "ntp_signd_accept: out of memory");
175                 return;
176         }
177         ntp_signdconn->conn      = conn;
178         ntp_signdconn->ntp_signd         = ntp_signd;
179         conn->private    = ntp_signdconn;
180
181         ntp_signdconn->packet = packet_init(ntp_signdconn);
182         if (ntp_signdconn->packet == NULL) {
183                 ntp_signd_terminate_connection(ntp_signdconn, "ntp_signd_accept: out of memory");
184                 return;
185         }
186         packet_set_private(ntp_signdconn->packet, ntp_signdconn);
187         packet_set_socket(ntp_signdconn->packet, conn->socket);
188         packet_set_callback(ntp_signdconn->packet, ntp_signd_recv);
189         packet_set_full_request(ntp_signdconn->packet, packet_full_request_u32);
190         packet_set_error_handler(ntp_signdconn->packet, ntp_signd_recv_error);
191         packet_set_event_context(ntp_signdconn->packet, conn->event.ctx);
192         packet_set_fde(ntp_signdconn->packet, conn->event.fde);
193         packet_set_serialise(ntp_signdconn->packet);
194 }
195
196 static const struct stream_server_ops ntp_signd_stream_ops = {
197         .name                   = "ntp_signd",
198         .accept_connection      = ntp_signd_accept,
199         .recv_handler           = ntp_signd_recv_handler,
200         .send_handler           = ntp_signd_send
201 };
202
203 /*
204   startup the ntp_signd task
205 */
206 static void ntp_signd_task_init(struct task_server *task)
207 {
208         struct ntp_signd_server *ntp_signd;
209         NTSTATUS status;
210
211         const struct model_ops *model_ops;
212
213         const char *address = "/tmp/ux_demo";
214
215         /* within the ntp_signd task we want to be a single process, so
216            ask for the single process model ops and pass these to the
217            stream_setup_socket() call. */
218         model_ops = process_model_byname("single");
219         if (!model_ops) {
220                 DEBUG(0,("Can't find 'single' process model_ops\n"));
221                 return;
222         }
223
224         status = stream_setup_socket(ntp_signd->task->event_ctx, 
225                                      ntp_signd->task->lp_ctx,
226                                      model_ops, 
227                                      &ntp_signd_stream_ops, 
228                                      "unix", address, NULL,
229                                      lp_socket_options(ntp_signd->task->lp_ctx), 
230                                      ntp_signd);
231         if (!NT_STATUS_IS_OK(status)) {
232                 DEBUG(0,("Failed to bind to %s - %s\n",
233                          address, nt_errstr(status)));
234                 return;
235         }
236
237         task_server_set_title(task, "task[ntp_signd]");
238
239         ntp_signd = talloc(task, struct ntp_signd_server);
240         if (ntp_signd == NULL) {
241                 task_server_terminate(task, "ntp_signd: out of memory");
242                 return;
243         }
244
245         ntp_signd->task = task;
246
247         ntp_signd->samdb = samdb_connect(ntp_signd, task->event_ctx, task->lp_ctx, anonymous_session(ntp_signd, task->event_ctx, task->lp_ctx));
248         if (ntp_signd->samdb == NULL) {
249                 task_server_terminate(task, "ntp_signd failed to open samdb");
250                 return;
251         }
252
253 }
254
255
256 /* called at smbd startup - register ourselves as a server service */
257 NTSTATUS server_service_ntp_signd_init(void)
258 {
259         return register_server_service("ntp_signd", ntp_signd_task_init);
260 }