CID 1311763: Fix incorrect return value
[garming/samba-autobuild/.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         const char *target_domain_name;
137         if (req->in.logon.network == NULL) {
138                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
139         }
140         target_domain_name = req->in.logon.network->identity_info.domain_name.string;
141
142         domain = find_auth_domain(0, target_domain_name);
143         if (domain == NULL) {
144                 return NT_STATUS_NO_SUCH_USER;
145         }
146
147         DEBUG(5, ("wb_irpc_SamLogon called\n"));
148
149         return wb_irpc_forward_rpc_call(msg, msg,
150                                         winbind_event_context(),
151                                         req, NDR_WINBIND_SAMLOGON,
152                                         "winbind_SamLogon",
153                                         domain, IRPC_CALL_TIMEOUT);
154 }
155
156 static NTSTATUS wb_irpc_LogonControl(struct irpc_message *msg,
157                                      struct winbind_LogonControl *req)
158 {
159         TALLOC_CTX *frame = talloc_stackframe();
160         char *domain_name = NULL;
161         struct winbindd_domain *domain = NULL;
162
163         DEBUG(5, ("wb_irpc_LogonControl called\n"));
164
165         switch (req->in.function_code) {
166         case NETLOGON_CONTROL_REDISCOVER:
167         case NETLOGON_CONTROL_TC_QUERY:
168         case NETLOGON_CONTROL_CHANGE_PASSWORD:
169         case NETLOGON_CONTROL_TC_VERIFY:
170                 if (req->in.data->domain == NULL) {
171                         TALLOC_FREE(frame);
172                         return NT_STATUS_INVALID_PARAMETER;
173                 }
174
175                 domain_name = talloc_strdup(frame, req->in.data->domain);
176                 if (domain_name == NULL) {
177                         req->out.result = WERR_NOMEM;
178                         TALLOC_FREE(frame);
179                         return NT_STATUS_OK;
180                 }
181
182                 break;
183         default:
184                 TALLOC_FREE(frame);
185                 return NT_STATUS_NOT_IMPLEMENTED;
186         }
187
188         if (req->in.function_code == NETLOGON_CONTROL_REDISCOVER) {
189                 char *p = NULL;
190
191                 /*
192                  * NETLOGON_CONTROL_REDISCOVER
193                  * get's an optional \dcname appended to the domain name
194                  */
195                 p = strchr_m(domain_name, '\\');
196                 if (p != NULL) {
197                         *p = '\0';
198                 }
199         }
200
201         domain = find_domain_from_name_noinit(domain_name);
202         if (domain == NULL) {
203                 req->out.result = WERR_NO_SUCH_DOMAIN;
204                 TALLOC_FREE(frame);
205                 return NT_STATUS_OK;
206         }
207
208         TALLOC_FREE(frame);
209         return wb_irpc_forward_rpc_call(msg, msg,
210                                         winbind_event_context(),
211                                         req, NDR_WINBIND_LOGONCONTROL,
212                                         "winbind_LogonControl",
213                                         domain, 45 /* timeout */);
214 }
215
216 static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
217                                      struct winbind_GetForestTrustInformation *req)
218 {
219         struct winbindd_domain *domain = NULL;
220
221         if (req->in.trusted_domain_name == NULL) {
222                 req->out.result = WERR_NO_SUCH_DOMAIN;
223                 return NT_STATUS_OK;
224         }
225
226         domain = find_domain_from_name_noinit(req->in.trusted_domain_name);
227         if (domain == NULL) {
228                 req->out.result = WERR_NO_SUCH_DOMAIN;
229                 return NT_STATUS_OK;
230         }
231
232         /*
233          * checking for domain->internal and domain->primary
234          * makes sure we only do some work when running as DC.
235          */
236
237         if (domain->internal) {
238                 req->out.result = WERR_NO_SUCH_DOMAIN;
239                 return NT_STATUS_OK;
240         }
241
242         if (domain->primary) {
243                 req->out.result = WERR_NO_SUCH_DOMAIN;
244                 return NT_STATUS_OK;
245         }
246
247         DEBUG(5, ("wb_irpc_GetForestTrustInformation called\n"));
248
249         return wb_irpc_forward_rpc_call(msg, msg,
250                                         winbind_event_context(),
251                                         req, NDR_WINBIND_GETFORESTTRUSTINFORMATION,
252                                         "winbind_GetForestTrustInformation",
253                                         domain, 45 /* timeout */);
254 }
255
256 NTSTATUS wb_irpc_register(void)
257 {
258         NTSTATUS status;
259
260         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
261                                wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
262         if (!NT_STATUS_IS_OK(status)) {
263                 return status;
264         }
265         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SAMLOGON,
266                                wb_irpc_SamLogon, NULL);
267         if (!NT_STATUS_IS_OK(status)) {
268                 return status;
269         }
270         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
271                                WINBIND_LOGONCONTROL,
272                                wb_irpc_LogonControl, NULL);
273         if (!NT_STATUS_IS_OK(status)) {
274                 return status;
275         }
276         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
277                                WINBIND_GETFORESTTRUSTINFORMATION,
278                                wb_irpc_GetForestTrustInformation, NULL);
279         if (!NT_STATUS_IS_OK(status)) {
280                 return status;
281         }
282
283         return NT_STATUS_OK;
284 }