Remove now unneeded talloc ctx parameter from do_UnjoinConfig().
[jra/samba/.git] / source3 / libnet / libnet_join.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet Join Support
4  *  Copyright (C) Gerald (Jerry) Carter 2006
5  *  Copyright (C) Guenther Deschner 2007
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "libnet/libnet_join.h"
23 #include "libnet/libnet_proto.h"
24
25 static NTSTATUS do_DomainJoin(TALLOC_CTX *mem_ctx,
26                               struct libnet_JoinCtx *r)
27 {
28         struct cli_state *cli = NULL;
29         struct rpc_pipe_client *pipe_hnd = NULL;
30         const char *password = NULL;
31         POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
32         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
33         char *acct_name;
34         const char *const_acct_name;
35         uint32 user_rid;
36         uint32 num_rids, *name_types, *user_rids;
37         uint32 flags = 0x3e8;
38         uint32 acb_info = ACB_WSTRUST;
39         uint32 fields_present;
40         uchar pwbuf[532];
41         SAM_USERINFO_CTR ctr;
42         SAM_USER_INFO_25 p25;
43         const int infolevel = 25;
44         struct MD5Context md5ctx;
45         uchar md5buffer[16];
46         DATA_BLOB digested_session_key;
47         uchar md4_trust_password[16];
48
49         password = talloc_strdup(mem_ctx,
50                 generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
51         NT_STATUS_HAVE_NO_MEMORY(password);
52
53         status = cli_full_connection(&cli, NULL, r->in.server_name,
54                                      NULL, 0,
55                                      "IPC$", "IPC",
56                                      r->in.admin_account,
57                                      NULL, //r->in.domain_name,
58                                      r->in.password,
59                                      0, Undefined, NULL);
60
61         if (!NT_STATUS_IS_OK(status)) {
62                 goto done;
63         }
64
65         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
66         if (!pipe_hnd) {
67                 goto done;
68         }
69
70         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
71                                         SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
72         if (!NT_STATUS_IS_OK(status)) {
73                 goto done;
74         }
75
76         status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, &lsa_pol,
77                                                12,
78                                                &r->out.netbios_domain_name,
79                                                &r->out.dns_domain_name,
80                                                NULL,
81                                                NULL,
82                                                &r->out.domain_sid);
83
84         if (!NT_STATUS_IS_OK(status)) {
85                 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
86                                                       5,
87                                                       &r->out.netbios_domain_name,
88                                                       &r->out.domain_sid);
89                 if (!NT_STATUS_IS_OK(status)) {
90                         goto done;
91                 }
92         }
93
94         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
95         cli_rpc_pipe_close(pipe_hnd);
96
97         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
98         if (!pipe_hnd) {
99                 goto done;
100         }
101
102         status = rpccli_samr_connect(pipe_hnd, mem_ctx,
103                                      SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
104         if (!NT_STATUS_IS_OK(status)) {
105                 goto done;
106         }
107
108         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
109                                          SEC_RIGHTS_MAXIMUM_ALLOWED,
110                                          r->out.domain_sid,
111                                          &domain_pol);
112         if (!NT_STATUS_IS_OK(status)) {
113                 goto done;
114         }
115
116         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
117         strlower_m(acct_name);
118         const_acct_name = acct_name;
119
120         status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
121                                              acct_name, ACB_WSTRUST,
122                                              0xe005000b, &user_pol, &user_rid);
123         if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
124                 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
125                         goto done;
126                 }
127         }
128
129         if (NT_STATUS_IS_OK(status)) {
130                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
131         }
132
133         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
134                                           &domain_pol, flags, 1,
135                                           &const_acct_name,
136                                           &num_rids, &user_rids, &name_types);
137         if (!NT_STATUS_IS_OK(status)) {
138                 goto done;
139         }
140
141         if (name_types[0] != SID_NAME_USER) {
142                 status = NT_STATUS_INVALID_WORKSTATION;
143                 goto done;
144         }
145
146         user_rid = user_rids[0];
147
148         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
149                                        SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
150                                        &user_pol);
151         if (!NT_STATUS_IS_OK(status)) {
152                 goto done;
153         }
154
155         E_md4hash(r->in.password, md4_trust_password);
156         encode_pw_buffer(pwbuf, r->in.password, STR_UNICODE);
157
158         generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
159         digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
160
161         MD5Init(&md5ctx);
162         MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
163         MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length);
164         MD5Final(digested_session_key.data, &md5ctx);
165
166         SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
167         memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
168
169         acb_info |= ACB_PWNOEXP;
170 #if 0
171         if ( dom_type == ND_TYPE_AD ) {
172 #if !defined(ENCTYPE_ARCFOUR_HMAC)
173                 acb_info |= ACB_USE_DES_KEY_ONLY;
174 #endif
175                 ;;
176         }
177 #endif
178         ZERO_STRUCT(ctr);
179         ZERO_STRUCT(p25);
180
181         fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
182         init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
183
184         ctr.switch_value = infolevel;
185         ctr.info.id25    = &p25;
186
187         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
188                                            infolevel, &cli->user_session_key,
189                                            &ctr);
190         if (!NT_STATUS_IS_OK(status)) {
191                 goto done;
192         }
193
194         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
195         cli_rpc_pipe_close(pipe_hnd);
196
197         if (!secrets_store_domain_sid(r->out.netbios_domain_name,
198                                       r->out.domain_sid))
199         {
200                 status = NT_STATUS_INTERNAL_DB_ERROR;
201                 goto done;
202         }
203
204         if (!secrets_store_machine_password(password,
205                                             r->out.netbios_domain_name,
206                                             SEC_CHAN_WKSTA))
207         {
208                 status = NT_STATUS_INTERNAL_DB_ERROR;
209                 goto done;
210         }
211
212         status = NT_STATUS_OK;
213  done:
214         if (cli) {
215                 cli_shutdown(cli);
216         }
217
218         return status;
219 }
220
221 static NTSTATUS do_DomainUnjoin(TALLOC_CTX *mem_ctx,
222                                 struct libnet_UnjoinCtx *r)
223 {
224         struct cli_state *cli = NULL;
225         struct rpc_pipe_client *pipe_hnd = NULL;
226         POLICY_HND sam_pol, domain_pol, user_pol;
227         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
228         char *acct_name;
229         uint32 flags = 0x3e8;
230         const char *const_acct_name;
231         uint32 user_rid;
232         uint32 num_rids, *name_types, *user_rids;
233         SAM_USERINFO_CTR ctr, *qctr = NULL;
234         SAM_USER_INFO_16 p16;
235
236         status = cli_full_connection(&cli, NULL, r->in.server_name,
237                                      NULL, 0,
238                                      "IPC$", "IPC",
239                                      r->in.admin_account,
240                                      NULL, //r->in.domain_name,
241                                      r->in.password,
242                                      0, Undefined, NULL);
243
244         if (!NT_STATUS_IS_OK(status)) {
245                 goto done;
246         }
247
248         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
249         if (!pipe_hnd) {
250                 goto done;
251         }
252
253         status = rpccli_samr_connect(pipe_hnd, mem_ctx,
254                                      SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
255         if (!NT_STATUS_IS_OK(status)) {
256                 goto done;
257         }
258
259         status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
260                                          SEC_RIGHTS_MAXIMUM_ALLOWED,
261                                          r->in.domain_sid,
262                                          &domain_pol);
263         if (!NT_STATUS_IS_OK(status)) {
264                 goto done;
265         }
266
267         acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
268         strlower_m(acct_name);
269         const_acct_name = acct_name;
270
271         status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
272                                           &domain_pol, flags, 1,
273                                           &const_acct_name,
274                                           &num_rids, &user_rids, &name_types);
275         if (!NT_STATUS_IS_OK(status)) {
276                 goto done;
277         }
278
279         if (name_types[0] != SID_NAME_USER) {
280                 status = NT_STATUS_INVALID_WORKSTATION;
281                 goto done;
282         }
283
284         user_rid = user_rids[0];
285
286         status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
287                                        SEC_RIGHTS_MAXIMUM_ALLOWED,
288                                        user_rid, &user_pol);
289         if (!NT_STATUS_IS_OK(status)) {
290                 goto done;
291         }
292
293         status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
294                                             &user_pol, 16, &qctr);
295         if (!NT_STATUS_IS_OK(status)) {
296                 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
297                 goto done;
298         }
299
300         ZERO_STRUCT(ctr);
301         ctr.switch_value = 16;
302         ctr.info.id16 = &p16;
303
304         p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
305
306         status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
307                                            &cli->user_session_key, &ctr);
308
309         rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
310
311         if (!secrets_delete_machine_password_ex(lp_workgroup())) {
312                 status = NT_STATUS_INTERNAL_DB_ERROR;
313                 goto done;
314         }
315
316         if (!secrets_delete_domain_sid(lp_workgroup())) {
317                 status = NT_STATUS_INTERNAL_DB_ERROR;
318                 goto done;
319         }
320
321 done:
322         rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
323         rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
324
325         cli_rpc_pipe_close(pipe_hnd);
326
327         if (cli) {
328                 cli_shutdown(cli);
329         }
330
331         return status;
332 }
333
334 static WERROR do_join_modify_vals_config(TALLOC_CTX *mem_ctx,
335                                          struct libnet_JoinCtx *r)
336 {
337         WERROR werr;
338         bool is_ad = false;
339
340         if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
341
342                 werr = libnet_smbconf_set_global_param("security", "user");
343                 W_ERROR_NOT_OK_RETURN(werr);
344
345                 werr = libnet_smbconf_set_global_param("workgroup",
346                                                        r->in.domain_name);
347                 return werr;
348         }
349
350         if (r->out.dns_domain_name) {
351                 is_ad = true;
352         }
353
354         werr = libnet_smbconf_set_global_param("security", "domain");
355         W_ERROR_NOT_OK_RETURN(werr);
356
357         werr = libnet_smbconf_set_global_param("workgroup",
358                                                r->out.netbios_domain_name);
359         W_ERROR_NOT_OK_RETURN(werr);
360
361         if (is_ad) {
362                 werr = libnet_smbconf_set_global_param("security", "ads");
363                 W_ERROR_NOT_OK_RETURN(werr);
364
365                 werr = libnet_smbconf_set_global_param("realm",
366                                                        r->out.dns_domain_name);
367                 W_ERROR_NOT_OK_RETURN(werr);
368         }
369
370         return werr;
371 }
372
373 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
374 {
375         WERROR werr = WERR_OK;
376
377         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
378
379                 werr = libnet_smbconf_set_global_param("security", "user");
380                 W_ERROR_NOT_OK_RETURN(werr);
381         }
382
383         werr = libnet_smbconf_delparm("GLOBAL", "realm");
384
385         return werr;
386 }
387
388
389 static WERROR do_JoinConfig(TALLOC_CTX *mem_ctx,
390                             struct libnet_JoinCtx *r)
391 {
392         WERROR werr;
393
394         if (!W_ERROR_IS_OK(r->out.result)) {
395                 return r->out.result;
396         }
397
398         if (!r->in.modify_config) {
399                 return WERR_OK;
400         }
401
402         werr = do_join_modify_vals_config(mem_ctx, r);
403         if (!W_ERROR_IS_OK(werr)) {
404                 return werr;
405         }
406
407         r->out.modified_config = true;
408         r->out.result = werr;
409
410         return werr;
411 }
412
413 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
414 {
415         WERROR werr;
416
417         if (!W_ERROR_IS_OK(r->out.result)) {
418                 return r->out.result;
419         }
420
421         if (!r->in.modify_config) {
422                 return WERR_OK;
423         }
424
425         werr = do_unjoin_modify_vals_config(r);
426         if (!W_ERROR_IS_OK(werr)) {
427                 return werr;
428         }
429
430         r->out.modified_config = true;
431         r->out.result = werr;
432
433         return werr;
434 }
435
436 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
437                            struct libnet_JoinCtx **r)
438 {
439         struct libnet_JoinCtx *ctx;
440
441         ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
442         if (!ctx) {
443                 return WERR_NOMEM;
444         }
445
446         *r = ctx;
447
448         return WERR_OK;
449 }
450
451 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
452                              struct libnet_UnjoinCtx **r)
453 {
454         struct libnet_UnjoinCtx *ctx;
455
456         ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
457         if (!ctx) {
458                 return WERR_NOMEM;
459         }
460
461         *r = ctx;
462
463         return WERR_OK;
464 }
465
466 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
467                    struct libnet_JoinCtx *r)
468 {
469         WERROR werr;
470         NTSTATUS status;
471
472         if (!r->in.domain_name) {
473                 return WERR_INVALID_PARAM;
474         }
475
476         if (r->in.modify_config && !lp_include_registry_globals()) {
477                 return WERR_NOT_SUPPORTED;
478         }
479
480         if (IS_DC) {
481                 return WERR_SETUP_DOMAIN_CONTROLLER;
482         }
483
484         if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
485
486                 status = do_DomainJoin(mem_ctx, r);
487                 if (!NT_STATUS_IS_OK(status)) {
488                         if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
489                                 return WERR_SETUP_ALREADY_JOINED;
490                         }
491                         return ntstatus_to_werror(status);
492                 }
493         }
494
495         werr = do_JoinConfig(mem_ctx, r);
496         if (!W_ERROR_IS_OK(werr)) {
497                 return werr;
498         }
499
500         return werr;
501 }
502
503 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
504                      struct libnet_UnjoinCtx *r)
505 {
506         WERROR werr;
507         NTSTATUS status;
508
509         if (r->in.modify_config && !lp_include_registry_globals()) {
510                 return WERR_NOT_SUPPORTED;
511         }
512
513         if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
514
515                 status = do_DomainUnjoin(mem_ctx, r);
516                 if (!NT_STATUS_IS_OK(status)) {
517                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
518                                 return WERR_SETUP_NOT_JOINED;
519                         }
520                         return ntstatus_to_werror(status);
521                 }
522         }
523
524         werr = do_UnjoinConfig(r);
525         if (!W_ERROR_IS_OK(werr)) {
526                 return werr;
527         }
528
529         return werr;
530 }