doc: add "spoolss: architecture" parameter usage
[mat/samba.git] / source4 / winbind / wb_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main winbindd server routines
4
5    Copyright (C) Stefan Metzmacher      2005-2008
6    Copyright (C) Andrew Tridgell        2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2010
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "smbd/process_model.h"
25 #include "winbind/wb_server.h"
26 #include "lib/stream/packet.h"
27 #include "lib/tsocket/tsocket.h"
28 #include "libcli/util/tstream.h"
29 #include "param/param.h"
30 #include "param/secrets.h"
31 #include "lib/util/dlinklist.h"
32
33 void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
34 {
35         struct wbsrv_service *service = wbconn->listen_socket->service;
36
37         if (wbconn->pending_calls == 0) {
38                 char *full_reason = talloc_asprintf(wbconn, "wbsrv: %s", reason);
39
40                 DLIST_REMOVE(service->broken_connections, wbconn);
41                 stream_terminate_connection(wbconn->conn, full_reason ? full_reason : reason);
42                 return;
43         }
44
45         if (wbconn->terminate != NULL) {
46                 return;
47         }
48
49         DEBUG(3,("wbsrv: terminating connection due to '%s' defered due to %d pending calls\n",
50                  reason, wbconn->pending_calls));
51         wbconn->terminate = talloc_strdup(wbconn, reason);
52         if (wbconn->terminate == NULL) {
53                 wbconn->terminate = "wbsrv: defered terminating connection - no memory";
54         }
55         DLIST_ADD_END(service->broken_connections, wbconn, NULL);
56 }
57
58 static void wbsrv_cleanup_broken_connections(struct wbsrv_service *s)
59 {
60         struct wbsrv_connection *cur, *next;
61
62         next = s->broken_connections;
63         while (next != NULL) {
64                 cur = next;
65                 next = cur->next;
66
67                 wbsrv_terminate_connection(cur, cur->terminate);
68         }
69 }
70
71 static void wbsrv_call_loop(struct tevent_req *subreq)
72 {
73         struct wbsrv_connection *wbsrv_conn = tevent_req_callback_data(subreq,
74                                       struct wbsrv_connection);
75         struct wbsrv_service *service = wbsrv_conn->listen_socket->service;
76         struct wbsrv_samba3_call *call;
77         NTSTATUS status;
78
79         if (wbsrv_conn->terminate) {
80                 /*
81                  * if the current connection is broken
82                  * we need to clean it up before any other connection
83                  */
84                 wbsrv_terminate_connection(wbsrv_conn, wbsrv_conn->terminate);
85                 wbsrv_cleanup_broken_connections(service);
86                 return;
87         }
88
89         wbsrv_cleanup_broken_connections(service);
90
91         call = talloc_zero(wbsrv_conn, struct wbsrv_samba3_call);
92         if (call == NULL) {
93                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_call_loop: "
94                                 "no memory for wbsrv_samba3_call");
95                 return;
96         }
97         call->wbconn = wbsrv_conn;
98
99         status = tstream_read_pdu_blob_recv(subreq,
100                                             call,
101                                             &call->in);
102         TALLOC_FREE(subreq);
103         if (!NT_STATUS_IS_OK(status)) {
104                 const char *reason;
105
106                 reason = talloc_asprintf(wbsrv_conn, "wbsrv_call_loop: "
107                                          "tstream_read_pdu_blob_recv() - %s",
108                                          nt_errstr(status));
109                 if (!reason) {
110                         reason = nt_errstr(status);
111                 }
112
113                 wbsrv_terminate_connection(wbsrv_conn, reason);
114                 return;
115         }
116
117         DEBUG(10,("Received winbind TCP packet of length %lu from %s\n",
118                  (long) call->in.length,
119                  tsocket_address_string(wbsrv_conn->conn->remote_address, call)));
120
121         status = wbsrv_samba3_process(call);
122         if (!NT_STATUS_IS_OK(status)) {
123                 const char *reason;
124
125                 reason = talloc_asprintf(wbsrv_conn, "wbsrv_call_loop: "
126                                          "tstream_read_pdu_blob_recv() - %s",
127                                          nt_errstr(status));
128                 if (!reason) {
129                         reason = nt_errstr(status);
130                 }
131
132                 wbsrv_terminate_connection(wbsrv_conn, reason);
133                 return;
134         }
135
136         /*
137          * The winbind pdu's has the length as 4 byte (initial_read_size),
138          * wbsrv_samba3_packet_full_request provides the pdu length then.
139          */
140         subreq = tstream_read_pdu_blob_send(wbsrv_conn,
141                                             wbsrv_conn->conn->event.ctx,
142                                             wbsrv_conn->tstream,
143                                             4, /* initial_read_size */
144                                             wbsrv_samba3_packet_full_request,
145                                             wbsrv_conn);
146         if (subreq == NULL) {
147                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_call_loop: "
148                                 "no memory for tstream_read_pdu_blob_send");
149                 return;
150         }
151         tevent_req_set_callback(subreq, wbsrv_call_loop, wbsrv_conn);
152 }
153
154 static void wbsrv_accept(struct stream_connection *conn)
155 {
156         struct wbsrv_listen_socket *wbsrv_socket = talloc_get_type(conn->private_data,
157                                                                    struct wbsrv_listen_socket);
158         struct wbsrv_connection *wbsrv_conn;
159         struct tevent_req *subreq;
160         int rc;
161
162         wbsrv_cleanup_broken_connections(wbsrv_socket->service);
163
164         wbsrv_conn = talloc_zero(conn, struct wbsrv_connection);
165         if (wbsrv_conn == NULL) {
166                 stream_terminate_connection(conn, "wbsrv_accept: out of memory");
167                 return;
168         }
169
170         wbsrv_conn->send_queue = tevent_queue_create(conn, "wbsrv_accept");
171         if (wbsrv_conn->send_queue == NULL) {
172                 stream_terminate_connection(conn,
173                                 "wbsrv_accept: out of memory");
174                 return;
175         }
176
177         TALLOC_FREE(conn->event.fde);
178
179         rc = tstream_bsd_existing_socket(wbsrv_conn,
180                         socket_get_fd(conn->socket),
181                         &wbsrv_conn->tstream);
182         if (rc < 0) {
183                 stream_terminate_connection(conn,
184                                 "wbsrv_accept: out of memory");
185                 return;
186         }
187
188         wbsrv_conn->conn = conn;
189         wbsrv_conn->listen_socket = wbsrv_socket;
190         wbsrv_conn->lp_ctx = wbsrv_socket->service->task->lp_ctx;
191         conn->private_data = wbsrv_conn;
192
193         /*
194          * The winbind pdu's has the length as 4 byte (initial_read_size),
195          * wbsrv_samba3_packet_full_request provides the pdu length then.
196          */
197         subreq = tstream_read_pdu_blob_send(wbsrv_conn,
198                                             wbsrv_conn->conn->event.ctx,
199                                             wbsrv_conn->tstream,
200                                             4, /* initial_read_size */
201                                             wbsrv_samba3_packet_full_request,
202                                             wbsrv_conn);
203         if (subreq == NULL) {
204                 wbsrv_terminate_connection(wbsrv_conn, "wbsrv_accept: "
205                                 "no memory for tstream_read_pdu_blob_send");
206                 return;
207         }
208         tevent_req_set_callback(subreq, wbsrv_call_loop, wbsrv_conn);
209 }
210
211 /*
212   called on a tcp recv
213 */
214 static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
215 {
216         struct wbsrv_connection *wbsrv_conn = talloc_get_type(conn->private_data,
217                                                         struct wbsrv_connection);
218         wbsrv_terminate_connection(wbsrv_conn, "wbsrv_recv: called");
219 }
220
221 /*
222   called when we can write to a connection
223 */
224 static void wbsrv_send(struct stream_connection *conn, uint16_t flags)
225 {
226         struct wbsrv_connection *wbsrv_conn = talloc_get_type(conn->private_data,
227                                                         struct wbsrv_connection);
228         /* this should never be triggered! */
229         wbsrv_terminate_connection(wbsrv_conn, "wbsrv_send: called");
230 }
231
232 static const struct stream_server_ops wbsrv_ops = {
233         .name                   = "winbind samba3 protocol",
234         .accept_connection      = wbsrv_accept,
235         .recv_handler           = wbsrv_recv,
236         .send_handler           = wbsrv_send
237 };
238
239 /*
240   startup the winbind task
241 */
242 static void winbind_task_init(struct task_server *task)
243 {
244         uint16_t port = 1;
245         const struct model_ops *model_ops;
246         NTSTATUS status;
247         struct wbsrv_service *service;
248         struct wbsrv_listen_socket *listen_socket;
249         char *errstring;
250         struct dom_sid *primary_sid;
251         bool ok;
252
253         task_server_set_title(task, "task[winbind]");
254
255         /* within the winbind task we want to be a single process, so
256            ask for the single process model ops and pass these to the
257            stream_setup_socket() call. */
258         model_ops = process_model_startup("single");
259         if (!model_ops) {
260                 task_server_terminate(task,
261                                       "Can't find 'single' process model_ops", true);
262                 return;
263         }
264
265         /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
266         ok = directory_create_or_exist_strict(lpcfg_winbindd_socket_directory(task->lp_ctx),
267                                               geteuid(), 0755);
268         if (!ok) {
269                 task_server_terminate(task,
270                                       "Cannot create winbindd pipe directory", true);
271                 return;
272         }
273
274         /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
275         ok = directory_create_or_exist_strict(lpcfg_winbindd_privileged_socket_directory(task->lp_ctx),
276                         geteuid(), 0750);
277         if (!ok) {
278                 task_server_terminate(task,
279                                       "Cannot create winbindd privileged pipe directory", true);
280                 return;
281         }
282
283         service = talloc_zero(task, struct wbsrv_service);
284         if (!service) goto nomem;
285         service->task   = task;
286
287
288         /* Find the primary SID, depending if we are a standalone
289          * server (what good is winbind in this case, but anyway...),
290          * or are in a domain as a member or a DC */
291         switch (lpcfg_server_role(service->task->lp_ctx)) {
292         case ROLE_STANDALONE:
293                 primary_sid = secrets_get_domain_sid(service,
294                                                      service->task->lp_ctx,
295                                                      lpcfg_netbios_name(service->task->lp_ctx),
296                                                      &service->sec_channel_type,
297                                                      &errstring);
298                 if (!primary_sid) {
299                         char *message = talloc_asprintf(task, 
300                                                         "Cannot start Winbind (standalone configuration): %s: "
301                                                         "Have you provisioned this server (%s) or changed it's name?", 
302                                                         errstring, lpcfg_netbios_name(service->task->lp_ctx));
303                         task_server_terminate(task, message, true);
304                         return;
305                 }
306                 break;
307         case ROLE_DOMAIN_MEMBER:
308                 primary_sid = secrets_get_domain_sid(service,
309                                                      service->task->lp_ctx,
310                                                      lpcfg_workgroup(service->task->lp_ctx),
311                                                      &service->sec_channel_type,
312                                                      &errstring);
313                 if (!primary_sid) {
314                         char *message = talloc_asprintf(task, "Cannot start Winbind (domain member): %s: "
315                                                         "Have you joined the %s domain?", 
316                                                         errstring, lpcfg_workgroup(service->task->lp_ctx));
317                         task_server_terminate(task, message, true);
318                         return;
319                 }
320                 break;
321         case ROLE_ACTIVE_DIRECTORY_DC:
322                 primary_sid = secrets_get_domain_sid(service,
323                                                      service->task->lp_ctx,
324                                                      lpcfg_workgroup(service->task->lp_ctx),
325                                                      &service->sec_channel_type,
326                                                      &errstring);
327                 if (!primary_sid) {
328                         char *message = talloc_asprintf(task, "Cannot start Winbind (domain controller): %s: "
329                                                         "Have you provisioned the %s domain?", 
330                                                         errstring, lpcfg_workgroup(service->task->lp_ctx));
331                         task_server_terminate(task, message, true);
332                         return;
333                 }
334                 break;
335         case ROLE_DOMAIN_PDC:
336         case ROLE_DOMAIN_BDC:
337                 task_server_terminate(task, "Cannot start 'samba' winbindd as a 'classic samba' DC: use winbindd instead", true);
338                 return;
339         }
340         service->primary_sid = primary_sid;
341
342         service->idmap_ctx = idmap_init(service, task->event_ctx, task->lp_ctx);
343         if (service->idmap_ctx == NULL) {
344                 task_server_terminate(task, "Failed to load idmap database", true);
345                 return;
346         }
347
348         service->priv_pipe_dir = lpcfg_winbindd_privileged_socket_directory(task->lp_ctx);
349         service->pipe_dir = lpcfg_winbindd_socket_directory(task->lp_ctx);
350
351         /* setup the unprivileged samba3 socket */
352         listen_socket = talloc(service, struct wbsrv_listen_socket);
353         if (!listen_socket) goto nomem;
354         listen_socket->socket_path      = talloc_asprintf(listen_socket, "%s/%s", 
355                                                           service->pipe_dir, 
356                                                           WINBINDD_SOCKET_NAME);
357         if (!listen_socket->socket_path) goto nomem;
358         listen_socket->service          = service;
359         listen_socket->privileged       = false;
360         status = stream_setup_socket(task, task->event_ctx, task->lp_ctx, model_ops,
361                                      &wbsrv_ops, "unix",
362                                      listen_socket->socket_path, &port,
363                                      lpcfg_socket_options(task->lp_ctx),
364                                      listen_socket);
365         if (!NT_STATUS_IS_OK(status)) goto listen_failed;
366
367         /* setup the privileged samba3 socket */
368         listen_socket = talloc(service, struct wbsrv_listen_socket);
369         if (!listen_socket) goto nomem;
370         listen_socket->socket_path 
371                 = talloc_asprintf(listen_socket, "%s/%s", 
372                                   service->priv_pipe_dir,
373                                   WINBINDD_SOCKET_NAME);
374         if (!listen_socket->socket_path) goto nomem;
375         listen_socket->service          = service;
376         listen_socket->privileged       = true;
377         status = stream_setup_socket(task, task->event_ctx, task->lp_ctx, model_ops,
378                                      &wbsrv_ops, "unix",
379                                      listen_socket->socket_path, &port,
380                                      lpcfg_socket_options(task->lp_ctx),
381                                      listen_socket);
382         if (!NT_STATUS_IS_OK(status)) goto listen_failed;
383
384         status = wbsrv_init_irpc(service);
385         if (!NT_STATUS_IS_OK(status)) goto irpc_failed;
386
387         return;
388
389 listen_failed:
390         DEBUG(0,("stream_setup_socket(path=%s) failed - %s\n",
391                  listen_socket->socket_path, nt_errstr(status)));
392         task_server_terminate(task, nt_errstr(status), true);
393         return;
394 irpc_failed:
395         DEBUG(0,("wbsrv_init_irpc() failed - %s\n",
396                  nt_errstr(status)));
397         task_server_terminate(task, nt_errstr(status), true);
398         return;
399 nomem:
400         task_server_terminate(task, nt_errstr(NT_STATUS_NO_MEMORY), true);
401         return;
402 }
403
404 /*
405   register ourselves as a available server
406 */
407 NTSTATUS server_service_winbind_init(void)
408 {
409         return register_server_service("winbind", winbind_task_init);
410 }