s4-winbind: Migrated winbind connection to tsocket.
[abartlet/samba.git/.git] / source4 / winbind / wb_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main winbindd server routines
4
5    Copyright (C) Stefan Metzmacher      2005
6    Copyright (C) Andrew Tridgell        2005
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 "smbd/process_model.h"
24 #include "winbind/wb_server.h"
25 #include "lib/stream/packet.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "libcli/util/tstream.h"
28 #include "param/param.h"
29
30 void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
31 {
32         stream_terminate_connection(wbconn->conn, reason);
33 }
34
35 static void wbsrv_call_loop(struct tevent_req *subreq)
36 {
37         struct wbsrv_connection *wbsrv_conn = tevent_req_callback_data(subreq,
38                                       struct wbsrv_connection);
39         struct wbsrv_samba3_call *call;
40         NTSTATUS status;
41
42         call = talloc_zero(wbsrv_conn, struct wbsrv_samba3_call);
43         if (call == NULL) {
44                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_call_loop: "
45                                 "no memory for wbsrv_samba3_call");
46                 return;
47         }
48         call->wbconn = wbsrv_conn;
49
50         status = tstream_read_pdu_blob_recv(subreq,
51                                             call,
52                                             &call->in);
53         TALLOC_FREE(subreq);
54         if (!NT_STATUS_IS_OK(status)) {
55                 const char *reason;
56
57                 reason = talloc_asprintf(call, "wbsrv_call_loop: "
58                                          "tstream_read_pdu_blob_recv() - %s",
59                                          nt_errstr(status));
60                 if (!reason) {
61                         reason = nt_errstr(status);
62                 }
63
64                 wbsrv_terminate_connection(wbsrv_conn, reason);
65                 return;
66         }
67
68         DEBUG(10,("Received winbind TCP packet of length %lu from %s\n",
69                  (long) call->in.length,
70                  tsocket_address_string(wbsrv_conn->conn->remote_address, call)));
71
72         status = wbsrv_samba3_process(call);
73         if (!NT_STATUS_IS_OK(status)) {
74                 const char *reason;
75
76                 reason = talloc_asprintf(call, "wbsrv_call_loop: "
77                                          "tstream_read_pdu_blob_recv() - %s",
78                                          nt_errstr(status));
79                 if (!reason) {
80                         reason = nt_errstr(status);
81                 }
82
83                 wbsrv_terminate_connection(wbsrv_conn, reason);
84                 return;
85         }
86
87         /*
88          * The winbind pdu's has the length as 4 byte (initial_read_size),
89          * wbsrv_samba3_packet_full_request provides the pdu length then.
90          */
91         subreq = tstream_read_pdu_blob_send(wbsrv_conn,
92                                             wbsrv_conn->conn->event.ctx,
93                                             wbsrv_conn->tstream,
94                                             4, /* initial_read_size */
95                                             wbsrv_samba3_packet_full_request,
96                                             wbsrv_conn);
97         if (subreq == NULL) {
98                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_call_loop: "
99                                 "no memory for tstream_read_pdu_blob_send");
100                 return;
101         }
102         tevent_req_set_callback(subreq, wbsrv_call_loop, wbsrv_conn);
103 }
104
105 static void wbsrv_accept(struct stream_connection *conn)
106 {
107         struct wbsrv_listen_socket *wbsrv_socket = talloc_get_type(conn->private_data,
108                                                                    struct wbsrv_listen_socket);
109         struct wbsrv_connection *wbsrv_conn;
110         struct tevent_req *subreq;
111         int rc;
112
113         wbsrv_conn = talloc_zero(conn, struct wbsrv_connection);
114         if (wbsrv_conn == NULL) {
115                 stream_terminate_connection(conn, "wbsrv_accept: out of memory");
116                 return;
117         }
118
119         wbsrv_conn->send_queue = tevent_queue_create(conn, "wbsrv_accept");
120         if (wbsrv_conn->send_queue == NULL) {
121                 stream_terminate_connection(conn,
122                                 "wbsrv_accept: out of memory");
123                 return;
124         }
125
126         TALLOC_FREE(conn->event.fde);
127
128         rc = tstream_bsd_existing_socket(wbsrv_conn->tstream,
129                         socket_get_fd(conn->socket),
130                         &wbsrv_conn->tstream);
131         if (rc < 0) {
132                 stream_terminate_connection(conn,
133                                 "wbsrv_accept: out of memory");
134                 return;
135         }
136
137         wbsrv_conn->conn = conn;
138         wbsrv_conn->listen_socket = wbsrv_socket;
139         wbsrv_conn->lp_ctx = wbsrv_socket->service->task->lp_ctx;
140         conn->private_data = wbsrv_conn;
141
142         /*
143          * The winbind pdu's has the length as 4 byte (initial_read_size),
144          * wbsrv_samba3_packet_full_request provides the pdu length then.
145          */
146         subreq = tstream_read_pdu_blob_send(wbsrv_conn,
147                                             wbsrv_conn->conn->event.ctx,
148                                             wbsrv_conn->tstream,
149                                             4, /* initial_read_size */
150                                             wbsrv_samba3_packet_full_request,
151                                             wbsrv_conn);
152         if (subreq == NULL) {
153                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_accept: "
154                                 "no memory for tstream_read_pdu_blob_send");
155                 return;
156         }
157         tevent_req_set_callback(subreq, wbsrv_call_loop, wbsrv_conn);
158 }
159
160 /*
161   called on a tcp recv
162 */
163 static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
164 {
165         struct wbsrv_connection *wbsrv_conn = talloc_get_type(conn->private_data,
166                                                         struct wbsrv_connection);
167         wbsrv_terminate_connection(wbsrv_conn, "wbsrv_recv: called");
168 }
169
170 /*
171   called when we can write to a connection
172 */
173 static void wbsrv_send(struct stream_connection *conn, uint16_t flags)
174 {
175         struct wbsrv_connection *wbsrv_conn = talloc_get_type(conn->private_data,
176                                                         struct wbsrv_connection);
177         /* this should never be triggered! */
178         wbsrv_terminate_connection(wbsrv_conn, "wbsrv_send: called");
179 }
180
181 static const struct stream_server_ops wbsrv_ops = {
182         .name                   = "winbind samba3 protocol",
183         .accept_connection      = wbsrv_accept,
184         .recv_handler           = wbsrv_recv,
185         .send_handler           = wbsrv_send
186 };
187
188 /*
189   startup the winbind task
190 */
191 static void winbind_task_init(struct task_server *task)
192 {
193         uint16_t port = 1;
194         const struct model_ops *model_ops;
195         NTSTATUS status;
196         struct wbsrv_service *service;
197         struct wbsrv_listen_socket *listen_socket;
198
199         task_server_set_title(task, "task[winbind]");
200
201         /* within the winbind task we want to be a single process, so
202            ask for the single process model ops and pass these to the
203            stream_setup_socket() call. */
204         model_ops = process_model_startup(task->event_ctx, "single");
205         if (!model_ops) {
206                 task_server_terminate(task,
207                                       "Can't find 'single' process model_ops", true);
208                 return;
209         }
210
211         /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
212         if (!directory_create_or_exist(lp_winbindd_socket_directory(task->lp_ctx), geteuid(), 0755)) {
213                 task_server_terminate(task,
214                                       "Cannot create winbindd pipe directory", true);
215                 return;
216         }
217
218         /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
219         if (!directory_create_or_exist(lp_winbindd_privileged_socket_directory(task->lp_ctx), geteuid(), 0750)) {
220                 task_server_terminate(task,
221                                       "Cannot create winbindd privileged pipe directory", true);
222                 return;
223         }
224
225         service = talloc_zero(task, struct wbsrv_service);
226         if (!service) goto nomem;
227         service->task   = task;
228
229         status = wbsrv_setup_domains(service);
230         if (!NT_STATUS_IS_OK(status)) {
231                 task_server_terminate(task, nt_errstr(status), true);
232                 return;
233         }
234
235         service->idmap_ctx = idmap_init(service, task->event_ctx, task->lp_ctx);
236         if (service->idmap_ctx == NULL) {
237                 task_server_terminate(task, "Failed to load idmap database", true);
238                 return;
239         }
240
241         /* setup the unprivileged samba3 socket */
242         listen_socket = talloc(service, struct wbsrv_listen_socket);
243         if (!listen_socket) goto nomem;
244         listen_socket->socket_path      = talloc_asprintf(listen_socket, "%s/%s", 
245                                                           lp_winbindd_socket_directory(task->lp_ctx), 
246                                                           WINBINDD_SAMBA3_SOCKET);
247         if (!listen_socket->socket_path) goto nomem;
248         listen_socket->service          = service;
249         listen_socket->privileged       = false;
250         status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
251                                      &wbsrv_ops, "unix",
252                                      listen_socket->socket_path, &port,
253                                      lp_socket_options(task->lp_ctx), 
254                                      listen_socket);
255         if (!NT_STATUS_IS_OK(status)) goto listen_failed;
256
257         /* setup the privileged samba3 socket */
258         listen_socket = talloc(service, struct wbsrv_listen_socket);
259         if (!listen_socket) goto nomem;
260         listen_socket->socket_path 
261                 = service->priv_socket_path 
262                 = talloc_asprintf(listen_socket, "%s/%s", 
263                                                           lp_winbindd_privileged_socket_directory(task->lp_ctx), 
264                                                           WINBINDD_SAMBA3_SOCKET);
265         if (!listen_socket->socket_path) goto nomem;
266         if (!listen_socket->socket_path) goto nomem;
267         listen_socket->service          = service;
268         listen_socket->privileged       = true;
269         status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
270                                      &wbsrv_ops, "unix",
271                                      listen_socket->socket_path, &port,
272                                      lp_socket_options(task->lp_ctx), 
273                                      listen_socket);
274         if (!NT_STATUS_IS_OK(status)) goto listen_failed;
275
276         status = wbsrv_init_irpc(service);
277         if (!NT_STATUS_IS_OK(status)) goto irpc_failed;
278
279         return;
280
281 listen_failed:
282         DEBUG(0,("stream_setup_socket(path=%s) failed - %s\n",
283                  listen_socket->socket_path, nt_errstr(status)));
284         task_server_terminate(task, nt_errstr(status), true);
285         return;
286 irpc_failed:
287         DEBUG(0,("wbsrv_init_irpc() failed - %s\n",
288                  nt_errstr(status)));
289         task_server_terminate(task, nt_errstr(status), true);
290         return;
291 nomem:
292         task_server_terminate(task, nt_errstr(NT_STATUS_NO_MEMORY), true);
293         return;
294 }
295
296 /*
297   register ourselves as a available server
298 */
299 NTSTATUS server_service_winbind_init(void)
300 {
301         return register_server_service("winbind", winbind_task_init);
302 }