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