winbindd: Print debug if we don't know how to route a wb_irpc_SamLogon() request
[metze/samba/wip.git] / source3 / winbindd / winbindd_irpc.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of commands submitted over IRPC
4    Copyright (C) Volker Lendecke 2009
5    Copyright (C) Guenther Deschner 2009
6    Copyright (C) Andrew Bartlett 2014
7    Copyright (C) Andrew Tridgell 2009
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 "winbindd.h"
25 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 #include "source4/lib/messaging/irpc.h"
27 #include "librpc/gen_ndr/ndr_winbind.h"
28
29 struct wb_irpc_forward_state {
30         struct irpc_message *msg;
31         struct winbind_DsrUpdateReadOnlyServerDnsRecords *req;
32
33         const char *opname;
34         struct dcesrv_call_state *dce_call;
35 };
36
37 /*
38   called when the forwarded rpc request is finished
39  */
40 static void wb_irpc_forward_callback(struct tevent_req *subreq)
41 {
42         struct wb_irpc_forward_state *st =
43                 tevent_req_callback_data(subreq,
44                 struct wb_irpc_forward_state);
45         const char *opname = st->opname;
46         NTSTATUS status;
47
48         status = dcerpc_binding_handle_call_recv(subreq);
49         TALLOC_FREE(subreq);
50         if (!NT_STATUS_IS_OK(status)) {
51                 DEBUG(0,("RPC callback failed for %s - %s\n",
52                          opname, nt_errstr(status)));
53                 irpc_send_reply(st->msg, status);
54                 return;
55         }
56
57         irpc_send_reply(st->msg, status);
58 }
59
60
61
62 /**
63  * Forward a RPC call using IRPC to another task
64  */
65
66 static NTSTATUS wb_irpc_forward_rpc_call(struct irpc_message *msg, TALLOC_CTX *mem_ctx,
67                                          struct tevent_context *ev,
68                                          void *r, uint32_t callid,
69                                          const char *opname,
70                                          struct winbindd_domain *domain,
71                                          uint32_t timeout)
72 {
73         struct wb_irpc_forward_state *st;
74         struct dcerpc_binding_handle *binding_handle;
75         struct tevent_req *subreq;
76
77         st = talloc(mem_ctx, struct wb_irpc_forward_state);
78         if (st == NULL) {
79                 return NT_STATUS_NO_MEMORY;
80         }
81
82         st->msg = msg;
83         st->opname   = opname;
84
85         binding_handle =  dom_child_handle(domain);
86         if (binding_handle == NULL) {
87                 DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
88                          opname, domain->name));
89                 return NT_STATUS_UNSUCCESSFUL;
90         }
91
92         /* reset timeout for the handle */
93         dcerpc_binding_handle_set_timeout(binding_handle, timeout);
94
95         /* forward the call */
96         subreq = dcerpc_binding_handle_call_send(st, ev,
97                                                  binding_handle,
98                                                  NULL, &ndr_table_winbind,
99                                                  callid,
100                                                  msg, r);
101         if (subreq == NULL) {
102                 DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
103                          opname, domain->name));
104                 return NT_STATUS_UNSUCCESSFUL;
105         }
106
107         /* mark the request as replied async */
108         msg->defer_reply = true;
109
110         /* setup the callback */
111         tevent_req_set_callback(subreq, wb_irpc_forward_callback, st);
112         return NT_STATUS_OK;
113 }
114
115 static NTSTATUS wb_irpc_DsrUpdateReadOnlyServerDnsRecords(struct irpc_message *msg,
116                                                    struct winbind_DsrUpdateReadOnlyServerDnsRecords *req)
117 {
118         struct winbindd_domain *domain = find_our_domain();
119         if (domain == NULL) {
120                 return NT_STATUS_NO_SUCH_DOMAIN;
121         }
122
123         DEBUG(5, ("wb_irpc_DsrUpdateReadOnlyServerDnsRecords called\n"));
124
125         return wb_irpc_forward_rpc_call(msg, msg,
126                                         winbind_event_context(),
127                                         req, NDR_WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
128                                         "winbind_DsrUpdateReadOnlyServerDnsRecords",
129                                         domain, IRPC_CALL_TIMEOUT);
130 }
131
132 static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
133                                  struct winbind_SamLogon *req)
134 {
135         struct winbindd_domain *domain;
136         struct netr_IdentityInfo *identity_info;
137         const char *target_domain_name = NULL;
138         const char *account_name = NULL;
139
140         switch (req->in.logon_level) {
141         case NetlogonInteractiveInformation:
142         case NetlogonServiceInformation:
143         case NetlogonInteractiveTransitiveInformation:
144         case NetlogonServiceTransitiveInformation:
145                 if (req->in.logon.password == NULL) {
146                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
147                 }
148                 identity_info = &req->in.logon.password->identity_info;
149                 break;
150
151         case NetlogonNetworkInformation:
152         case NetlogonNetworkTransitiveInformation:
153                 if (req->in.logon.network == NULL) {
154                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
155                 }
156
157                 identity_info = &req->in.logon.network->identity_info;
158                 break;
159
160         case NetlogonGenericInformation:
161                 if (req->in.logon.generic == NULL) {
162                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
163                 }
164
165                 identity_info = &req->in.logon.generic->identity_info;
166                 break;
167
168         default:
169                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
170         }
171
172         target_domain_name = identity_info->domain_name.string;
173         if (target_domain_name == NULL) {
174                 target_domain_name = "";
175         }
176
177         account_name = identity_info->account_name.string;
178         if (account_name == NULL) {
179                 account_name = "";
180         }
181
182         domain = find_auth_domain(0, target_domain_name);
183         if (domain == NULL) {
184                 DBG_INFO("target_domain[%s] for account[%s] not known\n",
185                         target_domain_name, account_name);
186                 req->out.result = NT_STATUS_NO_SUCH_USER;
187                 req->out.authoritative = 0;
188                 return NT_STATUS_OK;
189         }
190
191         DEBUG(5, ("wb_irpc_SamLogon called\n"));
192
193         return wb_irpc_forward_rpc_call(msg, msg,
194                                         winbind_event_context(),
195                                         req, NDR_WINBIND_SAMLOGON,
196                                         "winbind_SamLogon",
197                                         domain, IRPC_CALL_TIMEOUT);
198 }
199
200 static NTSTATUS wb_irpc_LogonControl(struct irpc_message *msg,
201                                      struct winbind_LogonControl *req)
202 {
203         TALLOC_CTX *frame = talloc_stackframe();
204         char *domain_name = NULL;
205         struct winbindd_domain *domain = NULL;
206
207         DEBUG(5, ("wb_irpc_LogonControl called\n"));
208
209         switch (req->in.function_code) {
210         case NETLOGON_CONTROL_REDISCOVER:
211         case NETLOGON_CONTROL_TC_QUERY:
212         case NETLOGON_CONTROL_CHANGE_PASSWORD:
213         case NETLOGON_CONTROL_TC_VERIFY:
214                 if (req->in.data->domain == NULL) {
215                         TALLOC_FREE(frame);
216                         return NT_STATUS_INVALID_PARAMETER;
217                 }
218
219                 domain_name = talloc_strdup(frame, req->in.data->domain);
220                 if (domain_name == NULL) {
221                         req->out.result = WERR_NOT_ENOUGH_MEMORY;
222                         TALLOC_FREE(frame);
223                         return NT_STATUS_OK;
224                 }
225
226                 break;
227         default:
228                 TALLOC_FREE(frame);
229                 return NT_STATUS_NOT_IMPLEMENTED;
230         }
231
232         if (req->in.function_code == NETLOGON_CONTROL_REDISCOVER) {
233                 char *p = NULL;
234
235                 /*
236                  * NETLOGON_CONTROL_REDISCOVER
237                  * get's an optional \dcname appended to the domain name
238                  */
239                 p = strchr_m(domain_name, '\\');
240                 if (p != NULL) {
241                         *p = '\0';
242                 }
243         }
244
245         domain = find_domain_from_name_noinit(domain_name);
246         if (domain == NULL) {
247                 req->out.result = WERR_NO_SUCH_DOMAIN;
248                 TALLOC_FREE(frame);
249                 return NT_STATUS_OK;
250         }
251
252         TALLOC_FREE(frame);
253         return wb_irpc_forward_rpc_call(msg, msg,
254                                         winbind_event_context(),
255                                         req, NDR_WINBIND_LOGONCONTROL,
256                                         "winbind_LogonControl",
257                                         domain, 45 /* timeout */);
258 }
259
260 static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
261                                      struct winbind_GetForestTrustInformation *req)
262 {
263         struct winbindd_domain *domain = NULL;
264
265         if (req->in.trusted_domain_name == NULL) {
266                 req->out.result = WERR_NO_SUCH_DOMAIN;
267                 return NT_STATUS_OK;
268         }
269
270         domain = find_domain_from_name_noinit(req->in.trusted_domain_name);
271         if (domain == NULL) {
272                 req->out.result = WERR_NO_SUCH_DOMAIN;
273                 return NT_STATUS_OK;
274         }
275
276         /*
277          * checking for domain->internal and domain->primary
278          * makes sure we only do some work when running as DC.
279          */
280
281         if (domain->internal) {
282                 req->out.result = WERR_NO_SUCH_DOMAIN;
283                 return NT_STATUS_OK;
284         }
285
286         if (domain->primary) {
287                 req->out.result = WERR_NO_SUCH_DOMAIN;
288                 return NT_STATUS_OK;
289         }
290
291         DEBUG(5, ("wb_irpc_GetForestTrustInformation called\n"));
292
293         return wb_irpc_forward_rpc_call(msg, msg,
294                                         winbind_event_context(),
295                                         req, NDR_WINBIND_GETFORESTTRUSTINFORMATION,
296                                         "winbind_GetForestTrustInformation",
297                                         domain, 45 /* timeout */);
298 }
299
300 static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg,
301                                   struct winbind_SendToSam *req)
302 {
303         /* TODO make sure that it is RWDC */
304         struct winbindd_domain *domain = find_our_domain();
305         if (domain == NULL) {
306                 return NT_STATUS_NO_SUCH_DOMAIN;
307         }
308
309         DEBUG(5, ("wb_irpc_SendToSam called\n"));
310
311         return wb_irpc_forward_rpc_call(msg, msg,
312                                         winbind_event_context(),
313                                         req, NDR_WINBIND_SENDTOSAM,
314                                         "winbind_SendToSam",
315                                         domain, IRPC_CALL_TIMEOUT);
316 }
317
318 NTSTATUS wb_irpc_register(void)
319 {
320         NTSTATUS status;
321
322         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
323                                wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
324         if (!NT_STATUS_IS_OK(status)) {
325                 return status;
326         }
327         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SAMLOGON,
328                                wb_irpc_SamLogon, NULL);
329         if (!NT_STATUS_IS_OK(status)) {
330                 return status;
331         }
332         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
333                                WINBIND_LOGONCONTROL,
334                                wb_irpc_LogonControl, NULL);
335         if (!NT_STATUS_IS_OK(status)) {
336                 return status;
337         }
338         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
339                                WINBIND_GETFORESTTRUSTINFORMATION,
340                                wb_irpc_GetForestTrustInformation, NULL);
341         if (!NT_STATUS_IS_OK(status)) {
342                 return status;
343         }
344         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SENDTOSAM,
345                                wb_irpc_SendToSam, NULL);
346         if (!NT_STATUS_IS_OK(status)) {
347                 return status;
348         }
349
350         return NT_STATUS_OK;
351 }