root/source4/ntp_signd/ntp_signd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ntp_signd_terminate_connection
  2. signing_failure
  3. ntp_signd_recv
  4. ntp_signd_recv_handler
  5. ntp_signd_recv_error
  6. ntp_signd_send
  7. ntp_signd_accept
  8. ntp_signd_task_init
  9. server_service_ntp_signd_init

   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/ndr_ntp_signd.h"
  31 #include "param/param.h"
  32 #include "dsdb/samdb/samdb.h"
  33 #include "auth/auth.h"
  34 #include "libcli/security/security.h"
  35 #include "lib/ldb/include/ldb.h"
  36 #include "lib/ldb/include/ldb_errors.h"
  37 #include "../lib/crypto/md5.h"
  38 #include "system/passwd.h"
  39 
  40 /*
  41   top level context structure for the ntp_signd server
  42 */
  43 struct ntp_signd_server {
  44         struct task_server *task;
  45         struct ldb_context *samdb;
  46 };
  47 
  48 /*
  49   state of an open connection
  50 */
  51 struct ntp_signd_connection {
  52         /* stream connection we belong to */
  53         struct stream_connection *conn;
  54 
  55         /* the ntp_signd_server the connection belongs to */
  56         struct ntp_signd_server *ntp_signd;
  57 
  58         struct packet_context *packet;
  59 };
  60 
  61 static void ntp_signd_terminate_connection(struct ntp_signd_connection *ntp_signdconn, const char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         stream_terminate_connection(ntp_signdconn->conn, reason);
  64 }
  65 
  66 static NTSTATUS signing_failure(struct ntp_signd_connection *ntp_signdconn,
     /* [<][>][^][v][top][bottom][index][help] */
  67                                 uint32_t packet_id) 
  68 {
  69         NTSTATUS status;
  70         struct signed_reply signed_reply;
  71         TALLOC_CTX *tmp_ctx = talloc_new(ntp_signdconn);
  72         DATA_BLOB reply, blob;
  73         enum ndr_err_code ndr_err;
  74 
  75         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
  76 
  77         signed_reply.version = 1;
  78         signed_reply.op = SIGNING_FAILURE;
  79         signed_reply.packet_id = packet_id;
  80         signed_reply.signed_packet = data_blob(NULL, 0);
  81         
  82         ndr_err = ndr_push_struct_blob(&reply, tmp_ctx, 
  83                                        lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx),
  84                                        &signed_reply,
  85                                        (ndr_push_flags_fn_t)ndr_push_signed_reply);
  86 
  87         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  88                 DEBUG(1,("failed to push ntp error reply\n"));
  89                 talloc_free(tmp_ctx);
  90                 return ndr_map_error2ntstatus(ndr_err);
  91         }
  92 
  93         blob = data_blob_talloc(ntp_signdconn, NULL, reply.length + 4);
  94         if (!blob.data) {
  95                 talloc_free(tmp_ctx);
  96                 return NT_STATUS_NO_MEMORY;
  97         }
  98 
  99         RSIVAL(blob.data, 0, reply.length);
 100         memcpy(blob.data + 4, reply.data, reply.length);        
 101 
 102         status = packet_send(ntp_signdconn->packet, blob);
 103 
 104         /* the call isn't needed any more */
 105         talloc_free(tmp_ctx);
 106         
 107         return status;
 108 }
 109 
 110 /*
 111   receive a full packet on a NTP_SIGND connection
 112 */
 113 static NTSTATUS ntp_signd_recv(void *private_data, DATA_BLOB wrapped_input)
     /* [<][>][^][v][top][bottom][index][help] */
 114 {
 115         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(private_data,
 116                                                              struct ntp_signd_connection);
 117         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 118         TALLOC_CTX *tmp_ctx = talloc_new(ntp_signdconn);
 119         DATA_BLOB input, output, wrapped_output;
 120         const struct dom_sid *domain_sid;
 121         struct dom_sid *sid;
 122         struct sign_request sign_request;
 123         struct signed_reply signed_reply;
 124         enum ndr_err_code ndr_err;
 125         struct ldb_result *res;
 126         const char *attrs[] = { "unicodePwd", "userAccountControl", "cn", NULL };
 127         struct MD5Context ctx;
 128         struct samr_Password *nt_hash;
 129         uint32_t user_account_control;
 130         int ret;
 131 
 132         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
 133 
 134         talloc_steal(tmp_ctx, wrapped_input.data);
 135 
 136         input = data_blob_const(wrapped_input.data + 4, wrapped_input.length - 4); 
 137 
 138         ndr_err = ndr_pull_struct_blob_all(&input, tmp_ctx, 
 139                                            lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx),
 140                                            &sign_request,
 141                                            (ndr_pull_flags_fn_t)ndr_pull_sign_request);
 142 
 143         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 144                 DEBUG(1,("failed to parse ntp signing request\n"));
 145                 dump_data(1, input.data, input.length);
 146                 return ndr_map_error2ntstatus(ndr_err);
 147         }
 148 
 149         /* We need to implement 'check signature' and 'request server
 150          * to sign' operations at some point */
 151         if (sign_request.op != SIGN_TO_CLIENT) {
 152                 talloc_free(tmp_ctx);
 153                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 154         }
 155 
 156         domain_sid = samdb_domain_sid(ntp_signdconn->ntp_signd->samdb);
 157         if (!domain_sid) {
 158                 talloc_free(tmp_ctx);
 159                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 160         }
 161         
 162         /* The top bit is a 'key selector' */
 163         sid = dom_sid_add_rid(tmp_ctx, domain_sid, sign_request.key_id & 0x7FFFFFFF);
 164         if (!sid) {
 165                 talloc_free(tmp_ctx);
 166                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 167         }
 168 
 169         ret = ldb_search(ntp_signdconn->ntp_signd->samdb, tmp_ctx,
 170                                  &res, samdb_base_dn(ntp_signdconn->ntp_signd->samdb),
 171                                  LDB_SCOPE_SUBTREE, attrs, "(&(objectSid=%s)(objectClass=user))",
 172                                  dom_sid_string(tmp_ctx, sid));
 173         if (ret != LDB_SUCCESS) {
 174                 DEBUG(2, ("Failed to search for SID %s in SAM for NTP signing: %s\n", dom_sid_string(tmp_ctx, sid),
 175                           ldb_errstring(ntp_signdconn->ntp_signd->samdb)));
 176                 talloc_free(tmp_ctx);
 177                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 178         }
 179 
 180         if (res->count == 0) {
 181                 DEBUG(5, ("Failed to find SID %s in SAM for NTP signing\n", dom_sid_string(tmp_ctx, sid)));
 182         } else if (res->count != 1) {
 183                 DEBUG(1, ("Found SID %s %u times in SAM for NTP signing\n", dom_sid_string(tmp_ctx, sid), res->count));
 184                 talloc_free(tmp_ctx);
 185                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 186         }
 187 
 188         user_account_control = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
 189 
 190         if (user_account_control & UF_ACCOUNTDISABLE) {
 191                 DEBUG(1, ("Account %s for SID [%s] is disabled\n", ldb_dn_get_linearized(res->msgs[0]->dn), dom_sid_string(tmp_ctx, sid)));
 192                 talloc_free(tmp_ctx);
 193                 return NT_STATUS_ACCESS_DENIED;
 194         }
 195 
 196         if (!(user_account_control & (UF_INTERDOMAIN_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT))) {
 197                 DEBUG(1, ("Account %s for SID [%s] is not a trust account\n", ldb_dn_get_linearized(res->msgs[0]->dn), dom_sid_string(tmp_ctx, sid)));
 198                 talloc_free(tmp_ctx);
 199                 return NT_STATUS_ACCESS_DENIED;
 200         }
 201 
 202         nt_hash = samdb_result_hash(tmp_ctx, res->msgs[0], "unicodePwd");
 203         if (!nt_hash) {
 204                 DEBUG(1, ("No unicodePwd found on record of SID %s for NTP signing\n", dom_sid_string(tmp_ctx, sid)));
 205                 talloc_free(tmp_ctx);
 206                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 207         }
 208 
 209         /* Generate the reply packet */
 210         signed_reply.version = 1;
 211         signed_reply.packet_id = sign_request.packet_id;
 212         signed_reply.op = SIGNING_SUCCESS;
 213         signed_reply.signed_packet = data_blob_talloc(tmp_ctx, 
 214                                                       NULL,
 215                                                       sign_request.packet_to_sign.length + 20);
 216 
 217         if (!signed_reply.signed_packet.data) {
 218                 talloc_free(tmp_ctx);
 219                 return signing_failure(ntp_signdconn, sign_request.packet_id);
 220         }
 221 
 222         memcpy(signed_reply.signed_packet.data, sign_request.packet_to_sign.data, sign_request.packet_to_sign.length);
 223         SIVAL(signed_reply.signed_packet.data, sign_request.packet_to_sign.length, sign_request.key_id);
 224 
 225         /* Sign the NTP response with the unicodePwd */
 226         MD5Init(&ctx);
 227         MD5Update(&ctx, nt_hash->hash, sizeof(nt_hash->hash));
 228         MD5Update(&ctx, sign_request.packet_to_sign.data, sign_request.packet_to_sign.length);
 229         MD5Final(signed_reply.signed_packet.data + sign_request.packet_to_sign.length + 4, &ctx);
 230 
 231 
 232         /* Place it into the packet for the wire */
 233         ndr_err = ndr_push_struct_blob(&output, tmp_ctx, 
 234                                        lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx),
 235                                        &signed_reply,
 236                                        (ndr_push_flags_fn_t)ndr_push_signed_reply);
 237 
 238         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 239                 DEBUG(1,("failed to push ntp error reply\n"));
 240                 talloc_free(tmp_ctx);
 241                 return ndr_map_error2ntstatus(ndr_err);
 242         }
 243 
 244         wrapped_output = data_blob_talloc(ntp_signdconn, NULL, output.length + 4);
 245         if (!wrapped_output.data) {
 246                 talloc_free(tmp_ctx);
 247                 return NT_STATUS_NO_MEMORY;
 248         }
 249 
 250         /* The 'wire' transport for this is wrapped with a 4 byte network byte order length */
 251         RSIVAL(wrapped_output.data, 0, output.length);
 252         memcpy(wrapped_output.data + 4, output.data, output.length);    
 253 
 254         status = packet_send(ntp_signdconn->packet, wrapped_output);
 255 
 256         /* the call isn't needed any more */
 257         talloc_free(tmp_ctx);
 258         return status;
 259 }
 260 
 261 /*
 262   receive some data on a NTP_SIGND connection
 263 */
 264 static void ntp_signd_recv_handler(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 265 {
 266         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(conn->private_data,
 267                                                              struct ntp_signd_connection);
 268         packet_recv(ntp_signdconn->packet);
 269 }
 270 
 271 /*
 272   called on a tcp recv error
 273 */
 274 static void ntp_signd_recv_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 275 {
 276         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(private_data, struct ntp_signd_connection);
 277         ntp_signd_terminate_connection(ntp_signdconn, nt_errstr(status));
 278 }
 279 
 280 /*
 281   called when we can write to a connection
 282 */
 283 static void ntp_signd_send(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 284 {
 285         struct ntp_signd_connection *ntp_signdconn = talloc_get_type(conn->private_data,
 286                                                              struct ntp_signd_connection);
 287         packet_queue_run(ntp_signdconn->packet);
 288 }
 289 
 290 /*
 291   called when we get a new connection
 292 */
 293 static void ntp_signd_accept(struct stream_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 294 {
 295         struct ntp_signd_server *ntp_signd = talloc_get_type(conn->private_data, struct ntp_signd_server);
 296         struct ntp_signd_connection *ntp_signdconn;
 297 
 298         ntp_signdconn = talloc_zero(conn, struct ntp_signd_connection);
 299         if (!ntp_signdconn) {
 300                 stream_terminate_connection(conn, "ntp_signd_accept: out of memory");
 301                 return;
 302         }
 303         ntp_signdconn->conn      = conn;
 304         ntp_signdconn->ntp_signd         = ntp_signd;
 305         conn->private_data    = ntp_signdconn;
 306 
 307         ntp_signdconn->packet = packet_init(ntp_signdconn);
 308         if (ntp_signdconn->packet == NULL) {
 309                 ntp_signd_terminate_connection(ntp_signdconn, "ntp_signd_accept: out of memory");
 310                 return;
 311         }
 312         packet_set_private(ntp_signdconn->packet, ntp_signdconn);
 313         packet_set_socket(ntp_signdconn->packet, conn->socket);
 314         packet_set_callback(ntp_signdconn->packet, ntp_signd_recv);
 315         packet_set_full_request(ntp_signdconn->packet, packet_full_request_u32);
 316         packet_set_error_handler(ntp_signdconn->packet, ntp_signd_recv_error);
 317         packet_set_event_context(ntp_signdconn->packet, conn->event.ctx);
 318         packet_set_fde(ntp_signdconn->packet, conn->event.fde);
 319         packet_set_serialise(ntp_signdconn->packet);
 320 }
 321 
 322 static const struct stream_server_ops ntp_signd_stream_ops = {
 323         .name                   = "ntp_signd",
 324         .accept_connection      = ntp_signd_accept,
 325         .recv_handler           = ntp_signd_recv_handler,
 326         .send_handler           = ntp_signd_send
 327 };
 328 
 329 /*
 330   startup the ntp_signd task
 331 */
 332 static void ntp_signd_task_init(struct task_server *task)
     /* [<][>][^][v][top][bottom][index][help] */
 333 {
 334         struct ntp_signd_server *ntp_signd;
 335         NTSTATUS status;
 336 
 337         const struct model_ops *model_ops;
 338 
 339         const char *address;
 340 
 341         if (!directory_create_or_exist(lp_ntp_signd_socket_directory(task->lp_ctx), geteuid(), 0755)) {
 342                 char *error = talloc_asprintf(task, "Cannot create NTP signd pipe directory: %s", 
 343                                               lp_ntp_signd_socket_directory(task->lp_ctx));
 344                 task_server_terminate(task,
 345                                       error);
 346                 return;
 347         }
 348 
 349         /* within the ntp_signd task we want to be a single process, so
 350            ask for the single process model ops and pass these to the
 351            stream_setup_socket() call. */
 352         model_ops = process_model_startup(task->event_ctx, "single");
 353         if (!model_ops) {
 354                 DEBUG(0,("Can't find 'single' process model_ops\n"));
 355                 return;
 356         }
 357 
 358         task_server_set_title(task, "task[ntp_signd]");
 359 
 360         ntp_signd = talloc(task, struct ntp_signd_server);
 361         if (ntp_signd == NULL) {
 362                 task_server_terminate(task, "ntp_signd: out of memory");
 363                 return;
 364         }
 365 
 366         ntp_signd->task = task;
 367 
 368         /* Must be system to get at the password hashes */
 369         ntp_signd->samdb = samdb_connect(ntp_signd, task->event_ctx, task->lp_ctx, system_session(ntp_signd, task->lp_ctx));
 370         if (ntp_signd->samdb == NULL) {
 371                 task_server_terminate(task, "ntp_signd failed to open samdb");
 372                 return;
 373         }
 374 
 375         address = talloc_asprintf(ntp_signd, "%s/socket", lp_ntp_signd_socket_directory(task->lp_ctx));
 376 
 377         status = stream_setup_socket(ntp_signd->task->event_ctx, 
 378                                      ntp_signd->task->lp_ctx,
 379                                      model_ops, 
 380                                      &ntp_signd_stream_ops, 
 381                                      "unix", address, NULL,
 382                                      lp_socket_options(ntp_signd->task->lp_ctx), 
 383                                      ntp_signd);
 384         if (!NT_STATUS_IS_OK(status)) {
 385                 DEBUG(0,("Failed to bind to %s - %s\n",
 386                          address, nt_errstr(status)));
 387                 return;
 388         }
 389 
 390 }
 391 
 392 
 393 /* called at smbd startup - register ourselves as a server service */
 394 NTSTATUS server_service_ntp_signd_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 395 {
 396         return register_server_service("ntp_signd", ntp_signd_task_init);
 397 }

/* [<][>][^][v][top][bottom][index][help] */