winbindd: allow all possible logon levels in wb_irpc_SamLogon()
[samba.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
139         switch (req->in.logon_level) {
140         case NetlogonInteractiveInformation:
141         case NetlogonServiceInformation:
142         case NetlogonInteractiveTransitiveInformation:
143         case NetlogonServiceTransitiveInformation:
144                 if (req->in.logon.password == NULL) {
145                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
146                 }
147                 identity_info = &req->in.logon.password->identity_info;
148                 break;
149
150         case NetlogonNetworkInformation:
151         case NetlogonNetworkTransitiveInformation:
152                 if (req->in.logon.network == NULL) {
153                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
154                 }
155
156                 identity_info = &req->in.logon.network->identity_info;
157                 break;
158
159         case NetlogonGenericInformation:
160                 if (req->in.logon.generic == NULL) {
161                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
162                 }
163
164                 identity_info = &req->in.logon.generic->identity_info;
165                 break;
166
167         default:
168                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
169         }
170
171         target_domain_name = identity_info->domain_name.string;
172
173         domain = find_auth_domain(0, target_domain_name);
174         if (domain == NULL) {
175                 req->out.result = NT_STATUS_NO_SUCH_USER;
176                 req->out.authoritative = 0;
177                 return NT_STATUS_OK;
178         }
179
180         DEBUG(5, ("wb_irpc_SamLogon called\n"));
181
182         return wb_irpc_forward_rpc_call(msg, msg,
183                                         winbind_event_context(),
184                                         req, NDR_WINBIND_SAMLOGON,
185                                         "winbind_SamLogon",
186                                         domain, IRPC_CALL_TIMEOUT);
187 }
188
189 static NTSTATUS wb_irpc_LogonControl(struct irpc_message *msg,
190                                      struct winbind_LogonControl *req)
191 {
192         TALLOC_CTX *frame = talloc_stackframe();
193         char *domain_name = NULL;
194         struct winbindd_domain *domain = NULL;
195
196         DEBUG(5, ("wb_irpc_LogonControl called\n"));
197
198         switch (req->in.function_code) {
199         case NETLOGON_CONTROL_REDISCOVER:
200         case NETLOGON_CONTROL_TC_QUERY:
201         case NETLOGON_CONTROL_CHANGE_PASSWORD:
202         case NETLOGON_CONTROL_TC_VERIFY:
203                 if (req->in.data->domain == NULL) {
204                         TALLOC_FREE(frame);
205                         return NT_STATUS_INVALID_PARAMETER;
206                 }
207
208                 domain_name = talloc_strdup(frame, req->in.data->domain);
209                 if (domain_name == NULL) {
210                         req->out.result = WERR_NOT_ENOUGH_MEMORY;
211                         TALLOC_FREE(frame);
212                         return NT_STATUS_OK;
213                 }
214
215                 break;
216         default:
217                 TALLOC_FREE(frame);
218                 return NT_STATUS_NOT_IMPLEMENTED;
219         }
220
221         if (req->in.function_code == NETLOGON_CONTROL_REDISCOVER) {
222                 char *p = NULL;
223
224                 /*
225                  * NETLOGON_CONTROL_REDISCOVER
226                  * get's an optional \dcname appended to the domain name
227                  */
228                 p = strchr_m(domain_name, '\\');
229                 if (p != NULL) {
230                         *p = '\0';
231                 }
232         }
233
234         domain = find_domain_from_name_noinit(domain_name);
235         if (domain == NULL) {
236                 req->out.result = WERR_NO_SUCH_DOMAIN;
237                 TALLOC_FREE(frame);
238                 return NT_STATUS_OK;
239         }
240
241         TALLOC_FREE(frame);
242         return wb_irpc_forward_rpc_call(msg, msg,
243                                         winbind_event_context(),
244                                         req, NDR_WINBIND_LOGONCONTROL,
245                                         "winbind_LogonControl",
246                                         domain, 45 /* timeout */);
247 }
248
249 static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
250                                      struct winbind_GetForestTrustInformation *req)
251 {
252         struct winbindd_domain *domain = NULL;
253
254         if (req->in.trusted_domain_name == NULL) {
255                 req->out.result = WERR_NO_SUCH_DOMAIN;
256                 return NT_STATUS_OK;
257         }
258
259         domain = find_domain_from_name_noinit(req->in.trusted_domain_name);
260         if (domain == NULL) {
261                 req->out.result = WERR_NO_SUCH_DOMAIN;
262                 return NT_STATUS_OK;
263         }
264
265         /*
266          * checking for domain->internal and domain->primary
267          * makes sure we only do some work when running as DC.
268          */
269
270         if (domain->internal) {
271                 req->out.result = WERR_NO_SUCH_DOMAIN;
272                 return NT_STATUS_OK;
273         }
274
275         if (domain->primary) {
276                 req->out.result = WERR_NO_SUCH_DOMAIN;
277                 return NT_STATUS_OK;
278         }
279
280         DEBUG(5, ("wb_irpc_GetForestTrustInformation called\n"));
281
282         return wb_irpc_forward_rpc_call(msg, msg,
283                                         winbind_event_context(),
284                                         req, NDR_WINBIND_GETFORESTTRUSTINFORMATION,
285                                         "winbind_GetForestTrustInformation",
286                                         domain, 45 /* timeout */);
287 }
288
289 static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg,
290                                   struct winbind_SendToSam *req)
291 {
292         /* TODO make sure that it is RWDC */
293         struct winbindd_domain *domain = find_our_domain();
294         if (domain == NULL) {
295                 return NT_STATUS_NO_SUCH_DOMAIN;
296         }
297
298         DEBUG(5, ("wb_irpc_SendToSam called\n"));
299
300         return wb_irpc_forward_rpc_call(msg, msg,
301                                         winbind_event_context(),
302                                         req, NDR_WINBIND_SENDTOSAM,
303                                         "winbind_SendToSam",
304                                         domain, IRPC_CALL_TIMEOUT);
305 }
306
307 NTSTATUS wb_irpc_register(void)
308 {
309         NTSTATUS status;
310
311         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
312                                wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
313         if (!NT_STATUS_IS_OK(status)) {
314                 return status;
315         }
316         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SAMLOGON,
317                                wb_irpc_SamLogon, NULL);
318         if (!NT_STATUS_IS_OK(status)) {
319                 return status;
320         }
321         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
322                                WINBIND_LOGONCONTROL,
323                                wb_irpc_LogonControl, NULL);
324         if (!NT_STATUS_IS_OK(status)) {
325                 return status;
326         }
327         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
328                                WINBIND_GETFORESTTRUSTINFORMATION,
329                                wb_irpc_GetForestTrustInformation, NULL);
330         if (!NT_STATUS_IS_OK(status)) {
331                 return status;
332         }
333         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SENDTOSAM,
334                                wb_irpc_SendToSam, NULL);
335         if (!NT_STATUS_IS_OK(status)) {
336                 return status;
337         }
338
339         return NT_STATUS_OK;
340 }