root/source4/smbd/service_named_pipe.c

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

DEFINITIONS

This source file includes following definitions.
  1. named_pipe_handover_connection
  2. named_pipe_recv_auth_request
  3. named_pipe_recv
  4. named_pipe_send
  5. named_pipe_recv_error
  6. named_pipe_full_request
  7. named_pipe_accept
  8. stream_setup_named_pipe

   1 /*
   2    Unix SMB/CIFS implementation.
   3 
   4    helper functions for NAMED PIPE servers
   5 
   6    Copyright (C) Stefan (metze) Metzmacher      2008
   7 
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12 
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17 
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include <tevent.h>
  24 #include "lib/socket/socket.h"
  25 #include "smbd/service.h"
  26 #include "param/param.h"
  27 #include "auth/session.h"
  28 #include "auth/auth_sam_reply.h"
  29 #include "lib/stream/packet.h"
  30 #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
  31 #include "system/passwd.h"
  32 
  33 struct named_pipe_socket {
  34         const char *pipe_name;
  35         const char *pipe_path;
  36         const struct stream_server_ops *ops;
  37         void *private_data;
  38 };
  39 
  40 struct named_pipe_connection {
  41         struct stream_connection *connection;
  42         struct packet_context *packet;
  43         const struct named_pipe_socket *pipe_sock;
  44         NTSTATUS status;
  45 };
  46 
  47 static void named_pipe_handover_connection(void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
  48 {
  49         struct named_pipe_connection *pipe_conn = talloc_get_type(
  50                 private_data, struct named_pipe_connection);
  51         struct stream_connection *conn = pipe_conn->connection;
  52 
  53         TEVENT_FD_NOT_WRITEABLE(conn->event.fde);
  54 
  55         if (!NT_STATUS_IS_OK(pipe_conn->status)) {
  56                 stream_terminate_connection(conn, nt_errstr(pipe_conn->status));
  57                 return;
  58         }
  59 
  60         /*
  61          * remove the named_pipe layer together with its packet layer
  62          */
  63         conn->ops               = pipe_conn->pipe_sock->ops;
  64         conn->private_data      = pipe_conn->pipe_sock->private_data;
  65         talloc_free(pipe_conn);
  66 
  67         /* we're now ready to start receiving events on this stream */
  68         TEVENT_FD_READABLE(conn->event.fde);
  69 
  70         /*
  71          * hand over to the real pipe implementation,
  72          * now that we have setup the transport session_info
  73          */
  74         conn->ops->accept_connection(conn);
  75 
  76         DEBUG(10,("named_pipe_handover_connection[%s]: succeeded\n",
  77               conn->ops->name));
  78 }
  79 
  80 static NTSTATUS named_pipe_recv_auth_request(void *private_data,
     /* [<][>][^][v][top][bottom][index][help] */
  81                                              DATA_BLOB req_blob)
  82 {
  83         struct named_pipe_connection *pipe_conn = talloc_get_type(
  84                 private_data, struct named_pipe_connection);
  85         struct stream_connection *conn = pipe_conn->connection;
  86         enum ndr_err_code ndr_err;
  87         struct named_pipe_auth_req req;
  88         union netr_Validation val;
  89         struct auth_serversupplied_info *server_info;
  90         struct named_pipe_auth_rep rep;
  91         DATA_BLOB rep_blob;
  92         NTSTATUS status;
  93 
  94         /*
  95          * make sure nothing happens on the socket untill the
  96          * real implemenation takes over
  97          */
  98         packet_recv_disable(pipe_conn->packet);
  99 
 100         /*
 101          * TODO: check it's a root (uid == 0) pipe
 102          */
 103 
 104         ZERO_STRUCT(rep);
 105         rep.level = 0;
 106         rep.status = NT_STATUS_INTERNAL_ERROR;
 107 
 108         DEBUG(10,("named_pipe_auth: req_blob.length[%u]\n",
 109                   (unsigned int)req_blob.length));
 110         dump_data(10, req_blob.data, req_blob.length);
 111 
 112         /* parse the passed credentials */
 113         ndr_err = ndr_pull_struct_blob_all(
 114                         &req_blob,
 115                         pipe_conn,
 116                         lp_iconv_convenience(conn->lp_ctx),
 117                         &req,
 118                         (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
 119         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 120                 rep.status = ndr_map_error2ntstatus(ndr_err);
 121                 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
 122                           nt_errstr(rep.status)));
 123                 goto reply;
 124         }
 125 
 126         if (strcmp(NAMED_PIPE_AUTH_MAGIC, req.magic) != 0) {
 127                 DEBUG(2, ("named_pipe_auth_req: invalid magic '%s' != %s\n",
 128                           req.magic, NAMED_PIPE_AUTH_MAGIC));
 129                 rep.status = NT_STATUS_INVALID_PARAMETER;
 130                 goto reply;
 131         }
 132 
 133         switch (req.level) {
 134         case 0:
 135                 /*
 136                  * anon connection, we don't create a session info
 137                  * and leave it NULL
 138                  */
 139                 rep.level = 0;
 140                 rep.status = NT_STATUS_OK;
 141                 break;
 142         case 1:
 143                 val.sam3 = &req.info.info1;
 144 
 145                 rep.level = 1;
 146                 rep.status = make_server_info_netlogon_validation(pipe_conn,
 147                                                                   "TODO",
 148                                                                   3, &val,
 149                                                                   &server_info);
 150                 if (!NT_STATUS_IS_OK(rep.status)) {
 151                         DEBUG(2, ("make_server_info_netlogon_validation returned "
 152                                   "%s\n", nt_errstr(rep.status)));
 153                         goto reply;
 154                 }
 155 
 156                 /* setup the session_info on the connection */
 157                 rep.status = auth_generate_session_info(conn,
 158                                                         conn->event.ctx,
 159                                                         conn->lp_ctx,
 160                                                         server_info,
 161                                                         &conn->session_info);
 162                 if (!NT_STATUS_IS_OK(rep.status)) {
 163                         DEBUG(2, ("auth_generate_session_info failed: %s\n",
 164                                   nt_errstr(rep.status)));
 165                         goto reply;
 166                 }
 167 
 168                 break;
 169         default:
 170                 DEBUG(2, ("named_pipe_auth_req: unknown level %u\n",
 171                           req.level));
 172                 rep.level = 0;
 173                 rep.status = NT_STATUS_INVALID_LEVEL;
 174                 goto reply;
 175         }
 176 
 177 reply:
 178         /* create the output */
 179         ndr_err = ndr_push_struct_blob(&rep_blob, pipe_conn,
 180                         lp_iconv_convenience(conn->lp_ctx),
 181                         &rep,
 182                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
 183         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 184                 status = ndr_map_error2ntstatus(ndr_err);
 185                 DEBUG(2, ("Could not marshall named_pipe_auth_rep: %s\n",
 186                           nt_errstr(status)));
 187                 return status;
 188         }
 189 
 190         pipe_conn->status = rep.status;
 191 
 192         DEBUG(10,("named_pipe_auth reply[%u]\n", rep_blob.length));
 193         dump_data(10, rep_blob.data, rep_blob.length);
 194         status = packet_send_callback(pipe_conn->packet, rep_blob,
 195                                       named_pipe_handover_connection,
 196                                       pipe_conn);
 197         if (!NT_STATUS_IS_OK(status)) {
 198                 DEBUG(0, ("packet_send_callback returned %s\n",
 199                           nt_errstr(status)));
 200                 return status;
 201         }
 202 
 203         return NT_STATUS_OK;
 204 }
 205 
 206 /*
 207   called when a pipe socket becomes readable
 208 */
 209 static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 210 {
 211         struct named_pipe_connection *pipe_conn = talloc_get_type(
 212                 conn->private_data, struct named_pipe_connection);
 213 
 214         DEBUG(10,("named_pipe_recv\n"));
 215 
 216         packet_recv(pipe_conn->packet);
 217 }
 218 
 219 /*
 220   called when a pipe socket becomes writable
 221 */
 222 static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 223 {
 224         struct named_pipe_connection *pipe_conn = talloc_get_type(
 225                 conn->private_data, struct named_pipe_connection);
 226 
 227         packet_queue_run(pipe_conn->packet);
 228 }
 229 
 230 /*
 231   handle socket recv errors
 232 */
 233 static void named_pipe_recv_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235         struct named_pipe_connection *pipe_conn = talloc_get_type(
 236                 private_data, struct named_pipe_connection);
 237 
 238         stream_terminate_connection(pipe_conn->connection, nt_errstr(status));
 239 }
 240 
 241 static NTSTATUS named_pipe_full_request(void *private_data, DATA_BLOB blob, size_t *size)
     /* [<][>][^][v][top][bottom][index][help] */
 242 {
 243         if (blob.length < 8) {
 244                 return STATUS_MORE_ENTRIES;
 245         }
 246 
 247         if (memcmp(NAMED_PIPE_AUTH_MAGIC, &blob.data[4], 4) != 0) {
 248                 DEBUG(0,("named_pipe_full_request: wrong protocol\n"));
 249                 *size = blob.length;
 250                 /* the error will be handled in named_pipe_recv_auth_request */
 251                 return NT_STATUS_OK;
 252         }
 253 
 254         *size = 4 + RIVAL(blob.data, 0);
 255         if (*size > blob.length) {
 256                 return STATUS_MORE_ENTRIES;
 257         }
 258 
 259         return NT_STATUS_OK;
 260 }
 261 
 262 static void named_pipe_accept(struct stream_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 263 {
 264         struct named_pipe_socket *pipe_sock = talloc_get_type(
 265                 conn->private_data, struct named_pipe_socket);
 266         struct named_pipe_connection *pipe_conn;
 267 
 268         DEBUG(5,("named_pipe_accept\n"));
 269 
 270         pipe_conn = talloc_zero(conn, struct named_pipe_connection);
 271         if (!pipe_conn) {
 272                 stream_terminate_connection(conn, "out of memory");
 273                 return;
 274         }
 275 
 276         pipe_conn->packet = packet_init(pipe_conn);
 277         if (!pipe_conn->packet) {
 278                 stream_terminate_connection(conn, "out of memory");
 279                 return;
 280         }
 281         packet_set_private(pipe_conn->packet, pipe_conn);
 282         packet_set_socket(pipe_conn->packet, conn->socket);
 283         packet_set_callback(pipe_conn->packet, named_pipe_recv_auth_request);
 284         packet_set_full_request(pipe_conn->packet, named_pipe_full_request);
 285         packet_set_error_handler(pipe_conn->packet, named_pipe_recv_error);
 286         packet_set_event_context(pipe_conn->packet, conn->event.ctx);
 287         packet_set_fde(pipe_conn->packet, conn->event.fde);
 288         packet_set_serialise(pipe_conn->packet);
 289         packet_set_initial_read(pipe_conn->packet, 8);
 290 
 291         pipe_conn->pipe_sock = pipe_sock;
 292 
 293         pipe_conn->connection = conn;
 294         conn->private_data = pipe_conn;
 295 }
 296 
 297 static const struct stream_server_ops named_pipe_stream_ops = {
 298         .name                   = "named_pipe",
 299         .accept_connection      = named_pipe_accept,
 300         .recv_handler           = named_pipe_recv,
 301         .send_handler           = named_pipe_send,
 302 };
 303 
 304 NTSTATUS stream_setup_named_pipe(struct tevent_context *event_context,
     /* [<][>][^][v][top][bottom][index][help] */
 305                                  struct loadparm_context *lp_ctx,
 306                                  const struct model_ops *model_ops,
 307                                  const struct stream_server_ops *stream_ops,
 308                                  const char *pipe_name,
 309                                  void *private_data)
 310 {
 311         char *dirname;
 312         struct named_pipe_socket *pipe_sock;
 313         NTSTATUS status = NT_STATUS_NO_MEMORY;;
 314 
 315         pipe_sock = talloc(event_context, struct named_pipe_socket);
 316         if (pipe_sock == NULL) {
 317                 goto fail;
 318         }
 319 
 320         /* remember the details about the pipe */
 321         pipe_sock->pipe_name    = talloc_strdup(pipe_sock, pipe_name);
 322         if (pipe_sock->pipe_name == NULL) {
 323                 goto fail;
 324         }
 325 
 326         dirname = talloc_asprintf(pipe_sock, "%s/np", lp_ncalrpc_dir(lp_ctx));
 327         if (dirname == NULL) {
 328                 goto fail;
 329         }
 330 
 331         if (!directory_create_or_exist(dirname, geteuid(), 0700)) {
 332                 status = map_nt_error_from_unix(errno);
 333                 goto fail;
 334         }
 335 
 336         if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
 337                 pipe_name += 6;
 338         }
 339 
 340         pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
 341                                                pipe_name);
 342         if (pipe_sock->pipe_path == NULL) {
 343                 goto fail;
 344         }
 345 
 346         talloc_free(dirname);
 347 
 348         pipe_sock->ops          = stream_ops;
 349         pipe_sock->private_data = talloc_reference(pipe_sock, private_data);
 350 
 351         status = stream_setup_socket(event_context,
 352                                      lp_ctx,
 353                                      model_ops,
 354                                      &named_pipe_stream_ops,
 355                                      "unix",
 356                                      pipe_sock->pipe_path,
 357                                      NULL,
 358                                      NULL,
 359                                      pipe_sock);
 360         if (!NT_STATUS_IS_OK(status)) {
 361                 goto fail;
 362         }
 363         return NT_STATUS_OK;
 364 
 365  fail:
 366         talloc_free(pipe_sock);
 367         return status;
 368 }

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