s3: Attempt to fix bug 7665
[samba.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 #include "libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/cli_wkssvc.h"
29
30 /****************************************************************
31 ****************************************************************/
32
33 WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
34                        struct NetJoinDomain *r)
35 {
36         struct libnet_JoinCtx *j = NULL;
37         WERROR werr;
38
39         if (!r->in.domain) {
40                 return WERR_INVALID_PARAM;
41         }
42
43         werr = libnet_init_JoinCtx(mem_ctx, &j);
44         W_ERROR_NOT_OK_RETURN(werr);
45
46         j->in.domain_name = talloc_strdup(mem_ctx, r->in.domain);
47         W_ERROR_HAVE_NO_MEMORY(j->in.domain_name);
48
49         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
50                 NTSTATUS status;
51                 struct netr_DsRGetDCNameInfo *info = NULL;
52                 const char *dc = NULL;
53                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
54                                  DS_WRITABLE_REQUIRED |
55                                  DS_RETURN_DNS_NAME;
56                 status = dsgetdcname(mem_ctx, NULL, r->in.domain,
57                                      NULL, NULL, flags, &info);
58                 if (!NT_STATUS_IS_OK(status)) {
59                         libnetapi_set_error_string(mem_ctx,
60                                 "%s", get_friendly_nt_error_msg(status));
61                         return ntstatus_to_werror(status);
62                 }
63
64                 dc = strip_hostname(info->dc_unc);
65                 j->in.dc_name = talloc_strdup(mem_ctx, dc);
66                 W_ERROR_HAVE_NO_MEMORY(j->in.dc_name);
67         }
68
69         if (r->in.account_ou) {
70                 j->in.account_ou = talloc_strdup(mem_ctx, r->in.account_ou);
71                 W_ERROR_HAVE_NO_MEMORY(j->in.account_ou);
72         }
73
74         if (r->in.account) {
75                 j->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
76                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_account);
77         }
78
79         if (r->in.password) {
80                 j->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
81                 W_ERROR_HAVE_NO_MEMORY(j->in.admin_password);
82         }
83
84         j->in.join_flags = r->in.join_flags;
85         j->in.modify_config = true;
86         j->in.debug = true;
87
88         werr = libnet_Join(mem_ctx, j);
89         if (!W_ERROR_IS_OK(werr) && j->out.error_string) {
90                 libnetapi_set_error_string(mem_ctx, "%s", j->out.error_string);
91         }
92         TALLOC_FREE(j);
93
94         return werr;
95 }
96
97 /****************************************************************
98 ****************************************************************/
99
100 WERROR NetJoinDomain_r(struct libnetapi_ctx *ctx,
101                        struct NetJoinDomain *r)
102 {
103         struct rpc_pipe_client *pipe_cli = NULL;
104         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
105         NTSTATUS status;
106         WERROR werr;
107         unsigned int old_timeout = 0;
108
109         werr = libnetapi_open_pipe(ctx, r->in.server,
110                                    &ndr_table_wkssvc.syntax_id,
111                                    &pipe_cli);
112         if (!W_ERROR_IS_OK(werr)) {
113                 goto done;
114         }
115
116         if (r->in.password) {
117                 encode_wkssvc_join_password_buffer(ctx,
118                                                    r->in.password,
119                                                    &pipe_cli->auth->user_session_key,
120                                                    &encrypted_password);
121         }
122
123         old_timeout = rpccli_set_timeout(pipe_cli, 600000);
124
125         status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, talloc_tos(),
126                                                r->in.server,
127                                                r->in.domain,
128                                                r->in.account_ou,
129                                                r->in.account,
130                                                encrypted_password,
131                                                r->in.join_flags,
132                                                &werr);
133         if (!NT_STATUS_IS_OK(status)) {
134                 werr = ntstatus_to_werror(status);
135                 goto done;
136         }
137
138  done:
139         if (pipe_cli && old_timeout) {
140                 rpccli_set_timeout(pipe_cli, old_timeout);
141         }
142
143         return werr;
144 }
145 /****************************************************************
146 ****************************************************************/
147
148 WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
149                          struct NetUnjoinDomain *r)
150 {
151         struct libnet_UnjoinCtx *u = NULL;
152         struct dom_sid domain_sid;
153         const char *domain = NULL;
154         WERROR werr;
155
156         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
157                 return WERR_SETUP_NOT_JOINED;
158         }
159
160         werr = libnet_init_UnjoinCtx(mem_ctx, &u);
161         W_ERROR_NOT_OK_RETURN(werr);
162
163         if (lp_realm()) {
164                 domain = lp_realm();
165         } else {
166                 domain = lp_workgroup();
167         }
168
169         if (r->in.server_name) {
170                 u->in.dc_name = talloc_strdup(mem_ctx, r->in.server_name);
171                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
172         } else {
173                 NTSTATUS status;
174                 struct netr_DsRGetDCNameInfo *info = NULL;
175                 const char *dc = NULL;
176                 uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
177                                  DS_WRITABLE_REQUIRED |
178                                  DS_RETURN_DNS_NAME;
179                 status = dsgetdcname(mem_ctx, NULL, domain,
180                                      NULL, NULL, flags, &info);
181                 if (!NT_STATUS_IS_OK(status)) {
182                         libnetapi_set_error_string(mem_ctx,
183                                 "failed to find DC for domain %s: %s",
184                                 domain,
185                                 get_friendly_nt_error_msg(status));
186                         return ntstatus_to_werror(status);
187                 }
188
189                 dc = strip_hostname(info->dc_unc);
190                 u->in.dc_name = talloc_strdup(mem_ctx, dc);
191                 W_ERROR_HAVE_NO_MEMORY(u->in.dc_name);
192
193                 u->in.domain_name = domain;
194         }
195
196         if (r->in.account) {
197                 u->in.admin_account = talloc_strdup(mem_ctx, r->in.account);
198                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_account);
199         }
200
201         if (r->in.password) {
202                 u->in.admin_password = talloc_strdup(mem_ctx, r->in.password);
203                 W_ERROR_HAVE_NO_MEMORY(u->in.admin_password);
204         }
205
206         u->in.domain_name = domain;
207         u->in.unjoin_flags = r->in.unjoin_flags;
208         u->in.delete_machine_account = false;
209         u->in.modify_config = true;
210         u->in.debug = true;
211
212         u->in.domain_sid = &domain_sid;
213
214         werr = libnet_Unjoin(mem_ctx, u);
215         if (!W_ERROR_IS_OK(werr) && u->out.error_string) {
216                 libnetapi_set_error_string(mem_ctx, "%s", u->out.error_string);
217         }
218         TALLOC_FREE(u);
219
220         return werr;
221 }
222
223 /****************************************************************
224 ****************************************************************/
225
226 WERROR NetUnjoinDomain_r(struct libnetapi_ctx *ctx,
227                          struct NetUnjoinDomain *r)
228 {
229         struct rpc_pipe_client *pipe_cli = NULL;
230         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
231         NTSTATUS status;
232         WERROR werr;
233         unsigned int old_timeout = 0;
234
235         werr = libnetapi_open_pipe(ctx, r->in.server_name,
236                                    &ndr_table_wkssvc.syntax_id,
237                                    &pipe_cli);
238         if (!W_ERROR_IS_OK(werr)) {
239                 goto done;
240         }
241
242         if (r->in.password) {
243                 encode_wkssvc_join_password_buffer(ctx,
244                                                    r->in.password,
245                                                    &pipe_cli->auth->user_session_key,
246                                                    &encrypted_password);
247         }
248
249         old_timeout = rpccli_set_timeout(pipe_cli, 60000);
250
251         status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, talloc_tos(),
252                                                  r->in.server_name,
253                                                  r->in.account,
254                                                  encrypted_password,
255                                                  r->in.unjoin_flags,
256                                                  &werr);
257         if (!NT_STATUS_IS_OK(status)) {
258                 werr = ntstatus_to_werror(status);
259                 goto done;
260         }
261
262  done:
263         if (pipe_cli && old_timeout) {
264                 rpccli_set_timeout(pipe_cli, old_timeout);
265         }
266
267         return werr;
268 }
269
270 /****************************************************************
271 ****************************************************************/
272
273 WERROR NetGetJoinInformation_r(struct libnetapi_ctx *ctx,
274                                struct NetGetJoinInformation *r)
275 {
276         struct rpc_pipe_client *pipe_cli = NULL;
277         NTSTATUS status;
278         WERROR werr;
279         const char *buffer = NULL;
280
281         werr = libnetapi_open_pipe(ctx, r->in.server_name,
282                                    &ndr_table_wkssvc.syntax_id,
283                                    &pipe_cli);
284         if (!W_ERROR_IS_OK(werr)) {
285                 goto done;
286         }
287
288         status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, talloc_tos(),
289                                                       r->in.server_name,
290                                                       &buffer,
291                                                       (enum wkssvc_NetJoinStatus *)r->out.name_type,
292                                                       &werr);
293         if (!NT_STATUS_IS_OK(status)) {
294                 werr = ntstatus_to_werror(status);
295                 goto done;
296         }
297
298         *r->out.name_buffer = talloc_strdup(ctx, buffer);
299         W_ERROR_HAVE_NO_MEMORY(*r->out.name_buffer);
300
301  done:
302         return werr;
303 }
304
305 /****************************************************************
306 ****************************************************************/
307
308 WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
309                                struct NetGetJoinInformation *r)
310 {
311         if ((lp_security() == SEC_ADS) && lp_realm()) {
312                 *r->out.name_buffer = talloc_strdup(ctx, lp_realm());
313         } else {
314                 *r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
315         }
316         if (!*r->out.name_buffer) {
317                 return WERR_NOMEM;
318         }
319
320         switch (lp_server_role()) {
321                 case ROLE_DOMAIN_MEMBER:
322                 case ROLE_DOMAIN_PDC:
323                 case ROLE_DOMAIN_BDC:
324                         *r->out.name_type = NetSetupDomainName;
325                         break;
326                 case ROLE_STANDALONE:
327                 default:
328                         *r->out.name_type = NetSetupWorkgroupName;
329                         break;
330         }
331
332         return WERR_OK;
333 }
334
335 /****************************************************************
336 ****************************************************************/
337
338 WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
339                            struct NetGetJoinableOUs *r)
340 {
341 #ifdef WITH_ADS
342         NTSTATUS status;
343         ADS_STATUS ads_status;
344         ADS_STRUCT *ads = NULL;
345         struct netr_DsRGetDCNameInfo *info = NULL;
346         const char *dc = NULL;
347         uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
348                          DS_RETURN_DNS_NAME;
349
350         status = dsgetdcname(ctx, NULL, r->in.domain,
351                              NULL, NULL, flags, &info);
352         if (!NT_STATUS_IS_OK(status)) {
353                 libnetapi_set_error_string(ctx, "%s",
354                         get_friendly_nt_error_msg(status));
355                 return ntstatus_to_werror(status);
356         }
357
358         dc = strip_hostname(info->dc_unc);
359
360         ads = ads_init(info->domain_name, info->domain_name, dc);
361         if (!ads) {
362                 return WERR_GENERAL_FAILURE;
363         }
364
365         SAFE_FREE(ads->auth.user_name);
366         if (r->in.account) {
367                 ads->auth.user_name = SMB_STRDUP(r->in.account);
368         } else if (ctx->username) {
369                 ads->auth.user_name = SMB_STRDUP(ctx->username);
370         }
371
372         SAFE_FREE(ads->auth.password);
373         if (r->in.password) {
374                 ads->auth.password = SMB_STRDUP(r->in.password);
375         } else if (ctx->password) {
376                 ads->auth.password = SMB_STRDUP(ctx->password);
377         }
378
379         ads_status = ads_connect_user_creds(ads);
380         if (!ADS_ERR_OK(ads_status)) {
381                 ads_destroy(&ads);
382                 return WERR_DEFAULT_JOIN_REQUIRED;
383         }
384
385         ads_status = ads_get_joinable_ous(ads, ctx,
386                                           (char ***)r->out.ous,
387                                           (size_t *)r->out.ou_count);
388         if (!ADS_ERR_OK(ads_status)) {
389                 ads_destroy(&ads);
390                 return WERR_DEFAULT_JOIN_REQUIRED;
391         }
392
393         ads_destroy(&ads);
394         return WERR_OK;
395 #else
396         return WERR_NOT_SUPPORTED;
397 #endif
398 }
399
400 /****************************************************************
401 ****************************************************************/
402
403 WERROR NetGetJoinableOUs_r(struct libnetapi_ctx *ctx,
404                            struct NetGetJoinableOUs *r)
405 {
406         struct rpc_pipe_client *pipe_cli = NULL;
407         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
408         NTSTATUS status;
409         WERROR werr;
410
411         werr = libnetapi_open_pipe(ctx, r->in.server_name,
412                                    &ndr_table_wkssvc.syntax_id,
413                                    &pipe_cli);
414         if (!W_ERROR_IS_OK(werr)) {
415                 goto done;
416         }
417
418         if (r->in.password) {
419                 encode_wkssvc_join_password_buffer(ctx,
420                                                    r->in.password,
421                                                    &pipe_cli->auth->user_session_key,
422                                                    &encrypted_password);
423         }
424
425         status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, talloc_tos(),
426                                                    r->in.server_name,
427                                                    r->in.domain,
428                                                    r->in.account,
429                                                    encrypted_password,
430                                                    r->out.ou_count,
431                                                    r->out.ous,
432                                                    &werr);
433         if (!NT_STATUS_IS_OK(status)) {
434                 werr = ntstatus_to_werror(status);
435                 goto done;
436         }
437
438  done:
439         return werr;
440 }
441
442 /****************************************************************
443 ****************************************************************/
444
445 WERROR NetRenameMachineInDomain_r(struct libnetapi_ctx *ctx,
446                                   struct NetRenameMachineInDomain *r)
447 {
448         struct rpc_pipe_client *pipe_cli = NULL;
449         struct wkssvc_PasswordBuffer *encrypted_password = NULL;
450         NTSTATUS status;
451         WERROR werr;
452
453         werr = libnetapi_open_pipe(ctx, r->in.server_name,
454                                    &ndr_table_wkssvc.syntax_id,
455                                    &pipe_cli);
456         if (!W_ERROR_IS_OK(werr)) {
457                 goto done;
458         }
459
460         if (r->in.password) {
461                 encode_wkssvc_join_password_buffer(ctx,
462                                                    r->in.password,
463                                                    &pipe_cli->auth->user_session_key,
464                                                    &encrypted_password);
465         }
466
467         status = rpccli_wkssvc_NetrRenameMachineInDomain2(pipe_cli, talloc_tos(),
468                                                           r->in.server_name,
469                                                           r->in.new_machine_name,
470                                                           r->in.account,
471                                                           encrypted_password,
472                                                           r->in.rename_options,
473                                                           &werr);
474         if (!NT_STATUS_IS_OK(status)) {
475                 werr = ntstatus_to_werror(status);
476                 goto done;
477         }
478
479  done:
480         return werr;
481 }
482
483 /****************************************************************
484 ****************************************************************/
485
486 WERROR NetRenameMachineInDomain_l(struct libnetapi_ctx *ctx,
487                                   struct NetRenameMachineInDomain *r)
488 {
489         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetRenameMachineInDomain);
490 }