2 Unix SMB/CIFS implementation.
3 Main winbindd server routines
5 Copyright (C) Stefan Metzmacher 2005
6 Copyright (C) Andrew Tridgell 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "lib/socket/socket.h"
25 #include "system/dir.h"
26 #include "system/filesys.h"
27 #include "dlinklist.h"
28 #include "lib/events/events.h"
29 #include "smbd/service_task.h"
30 #include "smbd/service_stream.h"
31 #include "winbind/winbindd_nss.h"
33 #define WINBINDD_DIR "/tmp/.winbindd/"
34 #define WINBINDD_ECHO_SOCKET WINBINDD_DIR"echo"
35 #define WINBINDD_ADDR_PREFIX "127.0.255."
36 #define WINBINDD_ECHO_ADDR WINBINDD_ADDR_PREFIX"1"
37 #define WINBINDD_ECHO_PORT 55555
38 #define WINBINDD_SAMBA3_SOCKET WINBINDD_DIR"pipe"
41 state of an open winbind connection
43 struct wbserver_connection {
45 struct data_blob_list_item *send_queue;
50 called when we get a new connection
52 static void winbind_accept(struct stream_connection *conn)
54 struct wbserver_connection *wbconn;
56 wbconn = talloc_zero(conn, struct wbserver_connection);
57 wbconn->input = data_blob_talloc(wbconn, NULL, 1024);
59 conn->private = wbconn;
63 receive some data on a winbind connection
65 static void winbind_recv(struct stream_connection *conn, uint16_t flags)
67 struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
70 struct data_blob_list_item *q;
72 status = socket_recv(conn->socket, wbconn->input.data, wbconn->input.length, &nread, 0);
73 if (NT_STATUS_IS_ERR(status)) {
74 DEBUG(10,("socket_recv: %s\n",nt_errstr(status)));
75 stream_terminate_connection(conn, "socket_recv: failed\n");
79 /* just reflect the data back down the socket */
80 q = talloc(wbconn, struct data_blob_list_item);
82 stream_terminate_connection(conn, "winbind_recv: out of memory\n");
86 q->blob = data_blob_talloc(q, wbconn->input.data, nread);
87 if (q->blob.data == NULL) {
88 stream_terminate_connection(conn, "winbind_recv: out of memory\n");
92 DLIST_ADD_END(wbconn->send_queue, q, struct data_blob_list_item *);
94 EVENT_FD_WRITEABLE(conn->event.fde);
98 called when we can write to a connection
100 static void winbind_send(struct stream_connection *conn, uint16_t flags)
102 struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
104 while (wbconn->send_queue) {
105 struct data_blob_list_item *q = wbconn->send_queue;
109 status = socket_send(conn->socket, &q->blob, &sendlen, 0);
110 if (NT_STATUS_IS_ERR(status)) {
111 DEBUG(10,("socket_send() %s\n",nt_errstr(status)));
112 stream_terminate_connection(conn, "socket_send: failed\n");
115 if (!NT_STATUS_IS_OK(status)) {
119 q->blob.length -= sendlen;
120 q->blob.data += sendlen;
122 if (q->blob.length == 0) {
123 DLIST_REMOVE(wbconn->send_queue, q);
128 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
131 static const struct stream_server_ops winbind_echo_ops = {
132 .name = "winbind_echo",
133 .accept_connection = winbind_accept,
134 .recv_handler = winbind_recv,
135 .send_handler = winbind_send,
138 struct winbind3_connection {
139 struct winbindd_request *request;
140 struct winbindd_response *response;
145 static void winbind_samba3_accept(struct stream_connection *conn)
147 struct winbind3_connection *wbconn;
149 wbconn = talloc(conn, struct winbind3_connection);
150 if (wbconn == NULL) {
151 DEBUG(0, ("talloc failed\n"));
152 stream_terminate_connection(conn, "talloc failed");
156 wbconn->request = NULL;
157 wbconn->response = NULL;
158 ZERO_STRUCT(wbconn->partial);
159 conn->private = wbconn;
162 static void winbind_samba3_recv(struct stream_connection *conn, uint16_t flags)
164 struct winbind3_connection *wbconn =
165 talloc_get_type(conn->private, struct winbind3_connection);
166 size_t npending, received;
169 if (!NT_STATUS_IS_OK(socket_pending(conn->socket, &npending))) {
170 stream_terminate_connection(conn, "socket_pending() failed");
175 stream_terminate_connection(conn, "EOF from client");
179 if (wbconn->partial.length + npending >
180 sizeof(struct winbindd_request)) {
181 npending = sizeof(struct winbindd_request) -
182 wbconn->partial.length;
185 wbconn->partial.data =
186 talloc_realloc_size(wbconn, wbconn->partial.data,
187 wbconn->partial.length + npending);
188 if (wbconn->partial.data == NULL) {
189 stream_terminate_connection(conn, "talloc_realloc failed");
193 res = socket_recv(conn->socket,
194 &wbconn->partial.data[wbconn->partial.length],
195 npending, &received, 0);
197 if (!NT_STATUS_IS_OK(res)) {
198 DEBUG(5, ("sock_recv failed: %s\n", nt_errstr(res)));
199 stream_terminate_connection(conn, "talloc_realloc failed");
203 wbconn->partial.length += received;
205 if (wbconn->partial.length < sizeof(struct winbindd_request)) {
209 wbconn->request = (struct winbindd_request *)wbconn->partial.data;
211 SMB_ASSERT(wbconn->response == NULL);
213 wbconn->response = talloc_zero(wbconn, struct winbindd_response);
214 if (wbconn->response == NULL) {
215 stream_terminate_connection(conn, "talloc_zero failed");
219 wbconn->response->length = sizeof(struct winbindd_response);
220 wbconn->response->result = WINBINDD_ERROR;
222 if (wbconn->request->length != sizeof(struct winbindd_request)) {
223 DEBUG(10, ("Got invalid request length %d\n",
224 wbconn->request->length));
228 DEBUG(10, ("Got winbind request %d\n", wbconn->request->cmd));
230 switch(wbconn->request->cmd) {
231 case WINBINDD_INTERFACE_VERSION:
232 wbconn->response->result = WINBINDD_OK;
233 wbconn->response->data.interface_version =
234 WINBIND_INTERFACE_VERSION;
236 case WINBINDD_PRIV_PIPE_DIR:
237 wbconn->response->result = WINBINDD_OK;
238 wbconn->response->extra_data =
239 smbd_tmp_path(wbconn->response, "winbind_priv/pipe");
240 if (wbconn->response->extra_data == NULL) {
241 stream_terminate_connection(conn,
242 "smbd_tmp_path failed");
245 wbconn->response->length +=
246 strlen(wbconn->response->extra_data) + 1;
249 wbconn->response->result = WINBINDD_OK;
256 talloc_free(wbconn->partial.data);
257 wbconn->partial.data = NULL;
260 wbconn->partial.data = (char *)wbconn->response;
261 wbconn->partial.length = sizeof(struct winbindd_response);
263 EVENT_FD_NOT_READABLE(conn->event.fde);
264 EVENT_FD_WRITEABLE(conn->event.fde);
267 static void winbind_samba3_send(struct stream_connection *conn, uint16_t flags)
269 struct winbind3_connection *wbconn =
270 talloc_get_type(conn->private, struct winbind3_connection);
274 res = socket_send(conn->socket, &wbconn->partial, &nsent, 0);
275 if (!NT_STATUS_IS_OK(res)) {
276 stream_terminate_connection(conn, "socket_send() failed");
280 wbconn->partial.data += nsent;
281 wbconn->partial.length -= nsent;
283 if (wbconn->partial.length != 0) {
287 if (wbconn->response->extra_data != NULL) {
288 wbconn->partial.data = wbconn->response->extra_data;
289 wbconn->partial.length = wbconn->response->length -
290 sizeof(struct winbindd_response);
291 wbconn->response->extra_data = NULL;
295 talloc_free(wbconn->response);
296 wbconn->response = NULL;
297 wbconn->partial.data = NULL;
298 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
299 EVENT_FD_READABLE(conn->event.fde);
302 static const struct stream_server_ops winbind_samba3_ops = {
303 .name = "winbind_samba3",
304 .accept_connection = winbind_samba3_accept,
305 .recv_handler = winbind_samba3_recv,
306 .send_handler = winbind_samba3_send,
310 startup the winbind task
312 static void winbind_task_init(struct task_server *task)
315 const struct model_ops *model_ops;
318 /* within the winbind task we want to be a single process, so
319 ask for the single process model ops and pass these to the
320 stream_setup_socket() call. */
321 model_ops = process_model_byname("single");
323 task_server_terminate(task, "Can't find 'single' process model_ops");
327 /* Make sure the directory for NCALRPC exists */
328 if (!directory_exist(WINBINDD_DIR)) {
329 mkdir(WINBINDD_DIR, 0755);
332 status = stream_setup_socket(task->event_ctx, model_ops, &winbind_echo_ops,
333 "unix", WINBINDD_ECHO_SOCKET, &port, NULL);
334 if (!NT_STATUS_IS_OK(status)) {
335 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
336 WINBINDD_ECHO_SOCKET, nt_errstr(status)));
337 task_server_terminate(task, "winbind Failed to find to ECHO unix socket");
341 status = stream_setup_socket(task->event_ctx, model_ops,
342 &winbind_samba3_ops, "unix",
343 WINBINDD_SAMBA3_SOCKET, &port, NULL);
344 if (!NT_STATUS_IS_OK(status)) {
345 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
346 WINBINDD_ECHO_SOCKET, nt_errstr(status)));
347 task_server_terminate(task, "winbind Failed to find to "
348 "SAMBA3 unix socket");
352 port = WINBINDD_ECHO_PORT;
354 status = stream_setup_socket(task->event_ctx, model_ops, &winbind_echo_ops,
355 "ipv4", WINBINDD_ECHO_ADDR, &port, NULL);
356 if (!NT_STATUS_IS_OK(status)) {
357 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
358 WINBINDD_ECHO_ADDR, port, nt_errstr(status)));
359 task_server_terminate(task, "winbind Failed to find to ECHO tcp socket");
365 initialise the winbind server
367 static NTSTATUS winbind_init(struct event_context *event_ctx, const struct model_ops *model_ops)
369 return task_server_startup(event_ctx, model_ops, winbind_task_init);
373 register ourselves as a available server
375 NTSTATUS server_service_winbind_init(void)
377 return register_server_service("winbind", winbind_init);