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