dsgetdcname: use existing messaging_context if possible.
[ira/wip.git] / source3 / lib / netapi / joindomain.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Join Support
4  *  Copyright (C) Guenther Deschner 2007-2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26 #include "libnet/libnet.h"
27
28 /****************************************************************
29 ****************************************************************/
30
31 WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
32                        struct NetJoinDomain *r)
33 {
34         struct libnet_JoinCtx *j = NULL;
35         WERROR werr;
36
37         if (!r->in.domain) {
38                 return WERR_INVALID_PARAM;
39         }
40
41         werr = libnet_init_JoinCtx(mem_ctx, &j);
42         W_ERROR_NOT_OK_RETURN(werr);
43
44         j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
45         W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
46
47         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
48                 NTSTATUS status;
49                 struct netr_DsRGetDCNameInfo *info = NULL;
50                 const char *dc = NULL;
51                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
52                                  DS_WRITABLE_REQUIRED |
53                                  DS_RETURN_DNS_NAME;
54                 status = dsgetdcname(mem_ctx, NULL, r->in.domain,
55                                      NULL, NULL, flags, &info);
56                 if (!NT_STATUS_IS_OK(status)) {
57                         libnetapi_set_error_string(mem_ctx,
58                                 "%s", get_friendly_nt_error_msg(status));
59                         return ntstatus_to_werror(status);
60                 }
61
62                 dc = strip_hostname(info->dc_unc);
63                 j->in.dc_name = talloc_strdup(mem_ctx, dc);
64                 W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
65         }
66
67         if (r->in.account_ou) {
68                 j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
69                 W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
70         }
71
72         if (r->in.account) {
73                 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
74                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
75         }
76
77         if (r->in.password) {
78                 j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
79                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
80         }
81
82         j->in.join_flags = r->in.join_flags;
83         j->in.modify_config = true;
84         j->in.debug = true;
85
86         werr = libnet_Join(mem_ctx, j);
87         if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
88                 libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
89         }
90         TALLOC_FREE(j);
91
92         return werr;
93 }
94
95 /****************************************************************
96 ****************************************************************/
97
98 WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
99                        struct NetJoinDomain *r)
100 {
101         struct cli_state *cli = NULL;
102         struct rpc_pipe_client *pipe_cli = NULL;
103         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
104         NTSTATUS status;
105         WERROR werr;
106         unsigned int old_timeout = 0;
107
108         werr = libnetapi_open_ipc_connection(ctx, r->in.server, &cli);
109         if (!W_ERROR_IS_OK(werr)) {
110                 goto done;
111         }
112
113         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
114         if (!W_ERROR_IS_OK(werr)) {
115                 goto done;
116         }
117
118         if (r->in.password) {
119                 encode_wkssvc_join_password_buffer(ctx,
120                                                    r->in.password,
121                                                    &cli->user_session_key,
122                                                    &encrypted_password);
123         }
124
125         old_timeout = cli_set_timeout(cli, 600000);
126
127         status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, ctx,
128                                                r->in.server,
129                                                r->in.domain,
130                                                r->in.account_ou,
131                                                r->in.account,
132                                                encrypted_password,
133                                                r->in.join_flags,
134                                                &werr);
135         if (!NT_STATUS_IS_OK(status)) {
136                 werr = ntstatus_to_werror(status);
137                 goto done;
138         }
139
140  done:
141         if (cli) {
142                 if (old_timeout) {
143                         cli_set_timeout(cli, old_timeout);
144                 }
145         }
146
147         return werr;
148 }
149 /****************************************************************
150 ****************************************************************/
151
152 WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
153                          struct NetUnjoinDomain *r)
154 {
155         struct libnet_UnjoinCtx *u = NULL;
156         struct dom_sid domain_sid;
157         const char *domain = NULL;
158         WERROR werr;
159
160         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
161                 return WERR_SETUP_NOT_JOINED;
162         }
163
164         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
165         W_ERROR_NOT_OK_RETURN(werr);
166
167         if (lp_realm()) {
168                 domain = lp_realm();
169         } else {
170                 domain = lp_workgroup();
171         }
172
173         if (r->in.server_name) {
174                 u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
175                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
176         } else {
177                 NTSTATUS status;
178                 struct netr_DsRGetDCNameInfo *info = NULL;
179                 const char *dc = NULL;
180                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
181                                  DS_WRITABLE_REQUIRED |
182                                  DS_RETURN_DNS_NAME;
183                 status = dsgetdcname(mem_ctx, NULL, domain,
184                                      NULL, NULL, flags, &info);
185                 if (!NT_STATUS_IS_OK(status)) {
186                         libnetapi_set_error_string(mem_ctx,
187                                 "failed to find DC for domain %s: %s",
188                                 domain,
189                                 get_friendly_nt_error_msg(status));
190                         return ntstatus_to_werror(status);
191                 }
192
193                 dc = strip_hostname(info->dc_unc);
194                 u->in.dc_name = talloc_strdup(mem_ctx, dc);
195                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
196
197                 u->in.domain_name = domain;
198         }
199
200         if (r->in.account) {
201                 u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
202                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
203         }
204
205         if (r->in.password) {
206                 u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
207                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
208         }
209
210         u->in.domain_name = domain;
211         u->in.unjoin_flags = r->in.unjoin_flags;
212         u->in.modify_config = true;
213         u->in.debug = true;
214
215         u->in.domain_sid = &domain_sid;
216
217         werr = libnet_Unjoin(mem_ctx, u);
218         if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
219                 libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
220         }
221         TALLOC_FREE(u);
222
223         return werr;
224 }
225
226 /****************************************************************
227 ****************************************************************/
228
229 WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
230                          struct NetUnjoinDomain *r)
231 {
232         struct cli_state *cli = NULL;
233         struct rpc_pipe_client *pipe_cli = NULL;
234         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
235         NTSTATUS status;
236         WERROR werr;
237         unsigned int old_timeout = 0;
238
239         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
240         if (!W_ERROR_IS_OK(werr)) {
241                 goto done;
242         }
243
244         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
245         if (!W_ERROR_IS_OK(werr)) {
246                 goto done;
247         }
248
249         if (r->in.password) {
250                 encode_wkssvc_join_password_buffer(ctx,
251                                                    r->in.password,
252                                                    &cli->user_session_key,
253                                                    &encrypted_password);
254         }
255
256         old_timeout = cli_set_timeout(cli, 60000);
257
258         status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, ctx,
259                                                  r->in.server_name,
260                                                  r->in.account,
261                                                  encrypted_password,
262                                                  r->in.unjoin_flags,
263                                                  &werr);
264         if (!NT_STATUS_IS_OK(status)) {
265                 werr = ntstatus_to_werror(status);
266                 goto done;
267         }
268
269  done:
270         if (cli) {
271                 if (old_timeout) {
272                         cli_set_timeout(cli, old_timeout);
273                 }
274         }
275
276         return werr;
277 }
278
279 /****************************************************************
280 ****************************************************************/
281
282 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
283                                struct NetGetJoinInformation *r)
284 {
285         struct cli_state *cli = NULL;
286         struct rpc_pipe_client *pipe_cli = NULL;
287         NTSTATUS status;
288         WERROR werr;
289         const char *buffer = NULL;
290
291         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
292         if (!W_ERROR_IS_OK(werr)) {
293                 goto done;
294         }
295
296         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
297         if (!W_ERROR_IS_OK(werr)) {
298                 goto done;
299         }
300
301         status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, ctx,
302                                                       r->in.server_name,
303                                                       &buffer,
304                                                       (enum wkssvc_NetJoinStatus *)r->out.name_type,
305                                                       &werr);
306         if (!NT_STATUS_IS_OK(status)) {
307                 werr = ntstatus_to_werror(status);
308                 goto done;
309         }
310
311         *r->out.name_buffer = talloc_strdup(ctx, buffer);
312         W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
313
314  done:
315         return werr;
316 }
317
318 /****************************************************************
319 ****************************************************************/
320
321 WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
322                                struct NetGetJoinInformation *r)
323 {
324         if ((lp_security() == SEC_ADS) && lp_realm()) {
325                 *r->out.name_buffer = talloc_strdup(ctx, lp_realm());
326         } else {
327                 *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
328         }
329         if (!*r->out.name_buffer) {
330                 return WERR_NOMEM;
331         }
332
333         switch (lp_server_role()) {
334                 case ROLE_DOMAIN_MEMBER:
335                 case ROLE_DOMAIN_PDC:
336                 case ROLE_DOMAIN_BDC:
337                         *r->out.name_type = NetSetupDomainName;
338                         break;
339                 case ROLE_STANDALONE:
340                 default:
341                         *r->out.name_type = NetSetupWorkgroupName;
342                         break;
343         }
344
345         return WERR_OK;
346 }
347
348 /****************************************************************
349 ****************************************************************/
350
351 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
352                            struct NetGetJoinableOUs *r)
353 {
354 #ifdef WITH_ADS
355         NTSTATUS status;
356         ADS_STATUS ads_status;
357         ADS_STRUCT *ads = NULL;
358         struct netr_DsRGetDCNameInfo *info = NULL;
359         const char *dc = NULL;
360         uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
361                          DS_RETURN_DNS_NAME;
362
363         status = dsgetdcname(ctx, NULL, r->in.domain,
364                              NULL, NULL, flags, &info);
365         if (!NT_STATUS_IS_OK(status)) {
366                 libnetapi_set_error_string(ctx, "%s",
367                         get_friendly_nt_error_msg(status));
368                 return ntstatus_to_werror(status);
369         }
370
371         dc = strip_hostname(info->dc_unc);
372
373         ads = ads_init(r->in.domain, r->in.domain, dc);
374         if (!ads) {
375                 return WERR_GENERAL_FAILURE;
376         }
377
378         SAFE_FREE(ads->auth.user_name);
379         if (r->in.account) {
380                 ads->auth.user_name = SMB_STRDUP(r->in.account);
381         } else if (ctx->username) {
382                 ads->auth.user_name = SMB_STRDUP(ctx->username);
383         }
384
385         SAFE_FREE(ads->auth.password);
386         if (r->in.password) {
387                 ads->auth.password = SMB_STRDUP(r->in.password);
388         } else if (ctx->password) {
389                 ads->auth.password = SMB_STRDUP(ctx->password);
390         }
391
392         ads_status = ads_connect(ads);
393         if (!ADS_ERR_OK(ads_status)) {
394                 ads_destroy(&ads);
395                 return WERR_DEFAULT_JOIN_REQUIRED;
396         }
397
398         ads_status = ads_get_joinable_ous(ads, ctx,
399                                           (char ***)r->out.ous,
400                                           (size_t *)r->out.ou_count);
401         if (!ADS_ERR_OK(ads_status)) {
402                 ads_destroy(&ads);
403                 return WERR_DEFAULT_JOIN_REQUIRED;
404         }
405
406         ads_destroy(&ads);
407         return WERR_OK;
408 #else
409         return WERR_NOT_SUPPORTED;
410 #endif
411 }
412
413 /****************************************************************
414 ****************************************************************/
415
416 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
417                            struct NetGetJoinableOUs *r)
418 {
419         struct cli_state *cli = NULL;
420         struct rpc_pipe_client *pipe_cli = NULL;
421         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
422         NTSTATUS status;
423         WERROR werr;
424
425         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
426         if (!W_ERROR_IS_OK(werr)) {
427                 goto done;
428         }
429
430         werr = libnetapi_open_pipe(ctx, cli, PI_WKSSVC, &pipe_cli);
431         if (!W_ERROR_IS_OK(werr)) {
432                 goto done;
433         }
434
435         if (r->in.password) {
436                 encode_wkssvc_join_password_buffer(ctx,
437                                                    r->in.password,
438                                                    &cli->user_session_key,
439                                                    &encrypted_password);
440         }
441
442         status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
443                                                    r->in.server_name,
444                                                    r->in.domain,
445                                                    r->in.account,
446                                                    encrypted_password,
447                                                    r->out.ou_count,
448                                                    r->out.ous,
449                                                    &werr);
450         if (!NT_STATUS_IS_OK(status)) {
451                 werr = ntstatus_to_werror(status);
452                 goto done;
453         }
454
455  done:
456         if (cli) {
457                 cli_shutdown(cli);
458         }
459
460         return werr;
461 }