summaryrefslogtreecommitdiff
path: root/source4/rpc_server/dcerpc_np.c
blob: a1da60f7f6b1b952edba617e95948d66fd08176c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* 
   Unix SMB/CIFS implementation.
   DCE/RPC over named pipes support (glue between dcerpc and smb servers)

   Copyright (C) Jelmer Vernooij 2005

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "includes.h"
#include "lib/socket/socket.h"
#include "lib/events/events.h"
#include "rpc_server/dcerpc_server.h"
#include "ntvfs/ipc/ipc.h"

static NTSTATUS dcesrv_pipe_open (void *context_data, const char *path, struct auth_session_info *session_info, struct stream_connection *srv_conn, TALLOC_CTX *mem_ctx, void **private_data)
{
	NTSTATUS status;
	struct dcerpc_binding *ep_description;
	struct dcesrv_connection *dce_conn;

	ep_description = talloc(mem_ctx, struct dcerpc_binding);
	NT_STATUS_HAVE_NO_MEMORY(ep_description);

	/*
	  we're all set, now ask the dcerpc server subsystem to open the 
	  endpoint. At this stage the pipe isn't bound, so we don't
	  know what interface the user actually wants, just that they want
	  one of the interfaces attached to this pipe endpoint.
	*/
	ep_description->transport = NCACN_NP;
	ep_description->endpoint = talloc_reference(ep_description, path);

	/* The session info is refcount-increased in the 
	 * dcesrv_endpoint_search_connect() function
	 */
	status = dcesrv_endpoint_search_connect(context_data,
						mem_ctx,
						ep_description, 
						session_info,
						srv_conn,
						&dce_conn);
	talloc_free(ep_description);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	*private_data = dce_conn;

	return NT_STATUS_OK;
}

static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
{
	NTSTATUS status = NT_STATUS_OK;
	DATA_BLOB *blob = private_data;

	if (out->length > blob->length) {
		status = STATUS_BUFFER_OVERFLOW;
	}

	if (out->length < blob->length) {
		blob->length = out->length;
	}
	memcpy(blob->data, out->data, blob->length);
	*nwritten = blob->length;
	return status;
}


static NTSTATUS dcesrv_pipe_trans(void *private_data, DATA_BLOB *in, DATA_BLOB *out)
{
	struct dcesrv_connection *dce_conn = private_data;
	NTSTATUS status;

	/* pass the data to the dcerpc server. Note that we don't
	   expect this to fail, and things like NDR faults are not
	   reported at this stage. Those sorts of errors happen in the
	   dcesrv_output stage */
	status = dcesrv_input(dce_conn, in);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/*
	  now ask the dcerpc system for some output. This doesn't yet handle
	  async calls. Again, we only expect NT_STATUS_OK. If the call fails then
	  the error is encoded at the dcerpc level
	*/
	status = dcesrv_output(dce_conn, out, ipc_trans_dcesrv_output);
	if (NT_STATUS_IS_ERR(status)) {
		return status;
	}

	return status;
}

static NTSTATUS dcesrv_pipe_write(void *private_data, DATA_BLOB *out)
{
	struct dcesrv_connection *dce_conn = private_data;
	NTSTATUS status;
	
	status = dcesrv_input(dce_conn, out);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}
	return status;
}

static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
{
	DATA_BLOB *blob = private_data;

	if (out->length < blob->length) {
		blob->length = out->length;
	}
	memcpy(blob->data, out->data, blob->length);
	*nwritten = blob->length;
	return NT_STATUS_OK;
}

		
static NTSTATUS dcesrv_pipe_read(void *private_data, DATA_BLOB *in)
{
	struct dcesrv_connection *dce_conn = private_data;
	NTSTATUS status;
	
	status = dcesrv_output(dce_conn, in, ipc_readx_dcesrv_output);
	if (NT_STATUS_IS_ERR(status)) {
		return status;
	}

	return status;
}

const struct named_pipe_ops dce_pipe_ops = {
	.open = dcesrv_pipe_open,
	.write = dcesrv_pipe_write,
	.read = dcesrv_pipe_read,
	.trans = dcesrv_pipe_trans
};

/* Add named pipe endpoint */
NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, struct event_context *event_ctx, const struct model_ops *model_ops)
{
	NTSTATUS status;

	status = named_pipe_listen(e->ep_description->endpoint, &dce_pipe_ops, dce_ctx);
	if (NT_STATUS_IS_ERR(status)) {
		return status;
	}

	return NT_STATUS_OK;
}