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