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