Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libnet/libnet_join.c
Line
Count
Source
1
/*
2
 *  Unix SMB/CIFS implementation.
3
 *  libnet Join Support
4
 *  Copyright (C) Gerald (Jerry) Carter 2006
5
 *  Copyright (C) Guenther Deschner 2007-2008
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 "source3/include/client.h"
23
#include "source3/libsmb/proto.h"
24
#include "ads.h"
25
#include "libsmb/namequery.h"
26
#include "librpc/gen_ndr/ndr_libnet_join.h"
27
#include "libnet/libnet_join.h"
28
#include "libcli/auth/libcli_auth.h"
29
#include "../librpc/gen_ndr/ndr_samr_c.h"
30
#include "rpc_client/init_samr.h"
31
#include "../librpc/gen_ndr/ndr_lsa_c.h"
32
#include "rpc_client/cli_lsarpc.h"
33
#include "../librpc/gen_ndr/ndr_netlogon.h"
34
#include "rpc_client/cli_netlogon.h"
35
#include "lib/smbconf/smbconf.h"
36
#include "lib/smbconf/smbconf_reg.h"
37
#include "../libds/common/flags.h"
38
#include "secrets.h"
39
#include "rpc_client/init_lsa.h"
40
41
#include "rpc_client/cli_pipe.h"
42
#include "../libcli/security/security.h"
43
#include "passdb.h"
44
#include "../libcli/smb/smbXcli_base.h"
45
#include "lib/param/loadparm.h"
46
#include "libcli/auth/netlogon_creds_cli.h"
47
#include "auth/credentials/credentials.h"
48
#include "auth/gensec/gensec.h"
49
#include "libsmb/dsgetdcname.h"
50
#include "rpc_client/util_netlogon.h"
51
#include "libnet/libnet_join_offline.h"
52
53
/****************************************************************
54
****************************************************************/
55
56
#define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
57
0
  do { \
58
0
    char *str = NULL; \
59
0
    str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
60
0
    DEBUG(1,("libnet_Join:\n%s", str)); \
61
0
    TALLOC_FREE(str); \
62
0
  } while (0)
63
64
#define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
65
0
  LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
66
#define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
67
0
  LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
68
69
#define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
70
0
  do { \
71
0
    char *str = NULL; \
72
0
    str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
73
0
    DEBUG(1,("libnet_Unjoin:\n%s", str)); \
74
0
    TALLOC_FREE(str); \
75
0
  } while (0)
76
77
#define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
78
0
  LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
79
#define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
80
0
  LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
81
82
/****************************************************************
83
****************************************************************/
84
85
static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
86
           struct libnet_JoinCtx *r,
87
           const char *format, ...)
88
           PRINTF_ATTRIBUTE(3,4);
89
90
static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
91
           struct libnet_JoinCtx *r,
92
           const char *format, ...)
93
0
{
94
0
  va_list args;
95
96
0
  if (r->out.error_string) {
97
0
    return;
98
0
  }
99
100
0
  va_start(args, format);
101
0
  r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
102
0
  va_end(args);
103
0
}
104
105
/****************************************************************
106
****************************************************************/
107
108
static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
109
             struct libnet_UnjoinCtx *r,
110
             const char *format, ...)
111
             PRINTF_ATTRIBUTE(3,4);
112
113
static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
114
             struct libnet_UnjoinCtx *r,
115
             const char *format, ...)
116
0
{
117
0
  va_list args;
118
119
0
  if (r->out.error_string) {
120
0
    return;
121
0
  }
122
123
0
  va_start(args, format);
124
0
  r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
125
0
  va_end(args);
126
0
}
127
128
#ifdef HAVE_ADS
129
130
/****************************************************************
131
****************************************************************/
132
133
static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
134
             const char *netbios_domain_name,
135
             const char *dc_name,
136
             struct cli_credentials *creds,
137
             TALLOC_CTX *mem_ctx,
138
             ADS_STRUCT **ads)
139
0
{
140
0
  TALLOC_CTX *tmp_ctx = talloc_stackframe();
141
0
  ADS_STATUS status;
142
0
  ADS_STRUCT *my_ads = NULL;
143
144
0
  my_ads = ads_init(tmp_ctx,
145
0
        dns_domain_name,
146
0
        netbios_domain_name,
147
0
        dc_name,
148
0
        ADS_SASL_SEAL);
149
0
  if (!my_ads) {
150
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
151
0
    goto out;
152
0
  }
153
154
0
  status = ads_connect_creds(my_ads, creds);
155
0
  if (!ADS_ERR_OK(status)) {
156
0
    goto out;
157
0
  }
158
159
0
  *ads = talloc_move(mem_ctx, &my_ads);
160
161
0
  status = ADS_SUCCESS;
162
0
out:
163
0
  TALLOC_FREE(tmp_ctx);
164
0
  return status;
165
0
}
166
167
/****************************************************************
168
****************************************************************/
169
170
static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
171
            struct libnet_JoinCtx *r,
172
            bool use_machine_creds)
173
0
{
174
0
  ADS_STATUS status;
175
0
  struct cli_credentials *creds = NULL;
176
177
0
  if (use_machine_creds) {
178
0
    const char *username = NULL;
179
0
    NTSTATUS ntstatus;
180
181
0
    if (r->in.machine_name == NULL ||
182
0
        r->in.machine_password == NULL) {
183
0
      return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
184
0
    }
185
0
    if (r->out.dns_domain_name != NULL) {
186
0
      username = talloc_asprintf(mem_ctx, "%s$@%s",
187
0
               r->in.machine_name,
188
0
               r->out.dns_domain_name);
189
0
      if (username == NULL) {
190
0
        return ADS_ERROR(LDAP_NO_MEMORY);
191
0
      }
192
0
    } else {
193
0
      username = talloc_asprintf(mem_ctx, "%s$",
194
0
               r->in.machine_name);
195
0
      if (username == NULL) {
196
0
        return ADS_ERROR(LDAP_NO_MEMORY);
197
0
      }
198
0
    }
199
200
0
    ntstatus = ads_simple_creds(mem_ctx,
201
0
              r->out.netbios_domain_name,
202
0
              username,
203
0
              r->in.machine_password,
204
0
              &creds);
205
0
    if (!NT_STATUS_IS_OK(ntstatus)) {
206
0
      return ADS_ERROR_NT(ntstatus);
207
0
    }
208
0
  } else {
209
0
    creds = r->in.admin_credentials;
210
0
  }
211
212
0
  status = libnet_connect_ads(r->out.dns_domain_name,
213
0
            r->out.netbios_domain_name,
214
0
            r->in.dc_name,
215
0
            creds,
216
0
            r,
217
0
            &r->in.ads);
218
0
  if (!ADS_ERR_OK(status)) {
219
0
    libnet_join_set_error_string(mem_ctx, r,
220
0
      "failed to connect to AD: %s",
221
0
      ads_errstr(status));
222
0
    return status;
223
0
  }
224
225
0
  if (!r->out.netbios_domain_name) {
226
0
    r->out.netbios_domain_name = talloc_strdup(mem_ctx,
227
0
                 r->in.ads->server.workgroup);
228
0
    ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
229
0
  }
230
231
0
  if (!r->out.dns_domain_name) {
232
0
    r->out.dns_domain_name = talloc_strdup(mem_ctx,
233
0
                   r->in.ads->config.realm);
234
0
    ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
235
0
  }
236
237
0
  r->out.domain_is_ad = true;
238
239
0
  return ADS_SUCCESS;
240
0
}
241
242
/****************************************************************
243
****************************************************************/
244
245
static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
246
                 struct libnet_JoinCtx *r)
247
0
{
248
0
  return libnet_join_connect_ads(mem_ctx, r, false);
249
0
}
250
251
/****************************************************************
252
****************************************************************/
253
254
static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
255
              struct libnet_JoinCtx *r)
256
0
{
257
0
  return libnet_join_connect_ads(mem_ctx, r, true);
258
0
}
259
260
/****************************************************************
261
****************************************************************/
262
263
static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
264
              struct libnet_UnjoinCtx *r)
265
0
{
266
0
  ADS_STATUS status;
267
268
0
  status = libnet_connect_ads(r->in.domain_name,
269
0
            r->in.domain_name,
270
0
            r->in.dc_name,
271
0
            r->in.admin_credentials,
272
0
            r,
273
0
            &r->in.ads);
274
0
  if (!ADS_ERR_OK(status)) {
275
0
    libnet_unjoin_set_error_string(mem_ctx, r,
276
0
      "failed to connect to AD: %s",
277
0
      ads_errstr(status));
278
0
  }
279
280
0
  return status;
281
0
}
282
283
/****************************************************************
284
 join a domain using ADS (LDAP mods)
285
****************************************************************/
286
287
static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
288
                 struct libnet_JoinCtx *r)
289
0
{
290
0
  ADS_STATUS status;
291
0
  LDAPMessage *res = NULL;
292
0
  const char *attrs[] = { "dn", NULL };
293
0
  bool moved = false;
294
295
0
  status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
296
0
  if (!ADS_ERR_OK(status)) {
297
0
    return status;
298
0
  }
299
300
0
  status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
301
0
  if (!ADS_ERR_OK(status)) {
302
0
    return status;
303
0
  }
304
305
0
  if (ads_count_replies(r->in.ads, res) != 1) {
306
0
    ads_msgfree(r->in.ads, res);
307
0
    return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
308
0
  }
309
310
0
  ads_msgfree(r->in.ads, res);
311
312
  /* Attempt to create the machine account and bail if this fails.
313
     Assume that the admin wants exactly what they requested */
314
315
0
  if (r->in.machine_password == NULL) {
316
0
    r->in.machine_password =
317
0
      trust_pw_new_value(mem_ctx,
318
0
             r->in.secure_channel_type,
319
0
             SEC_ADS);
320
0
    if (r->in.machine_password == NULL) {
321
0
      return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
322
0
    }
323
0
  }
324
325
0
  status = ads_create_machine_acct(r->in.ads,
326
0
           r->in.machine_name,
327
0
           r->in.machine_password,
328
0
           r->in.account_ou,
329
0
           r->in.desired_encryption_types,
330
0
           r->out.dns_domain_name);
331
332
0
  if (ADS_ERR_OK(status)) {
333
0
    DBG_WARNING("Machine account successfully created\n");
334
0
    return status;
335
0
  } else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
336
0
        (status.err.rc == LDAP_ALREADY_EXISTS)) {
337
0
    status = ADS_SUCCESS;
338
0
  }
339
340
0
  if (!ADS_ERR_OK(status)) {
341
0
    DBG_WARNING("Failed to create machine account\n");
342
0
    return status;
343
0
  }
344
345
0
  status = ads_move_machine_acct(r->in.ads,
346
0
               r->in.machine_name,
347
0
               r->in.account_ou,
348
0
               &moved);
349
0
  if (!ADS_ERR_OK(status)) {
350
0
    DEBUG(1,("failure to locate/move pre-existing "
351
0
      "machine account\n"));
352
0
    return status;
353
0
  }
354
355
0
  DEBUG(1,("The machine account %s the specified OU.\n",
356
0
    moved ? "was moved into" : "already exists in"));
357
358
0
  return status;
359
0
}
360
361
/****************************************************************
362
****************************************************************/
363
364
static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
365
                struct libnet_UnjoinCtx *r)
366
0
{
367
0
  ADS_STATUS status;
368
369
0
  if (!r->in.ads) {
370
0
    status = libnet_unjoin_connect_ads(mem_ctx, r);
371
0
    if (!ADS_ERR_OK(status)) {
372
0
      libnet_unjoin_set_error_string(mem_ctx, r,
373
0
        "failed to connect to AD: %s",
374
0
        ads_errstr(status));
375
0
      return status;
376
0
    }
377
0
  }
378
379
0
  status = ads_leave_realm(r->in.ads, r->in.machine_name);
380
0
  if (!ADS_ERR_OK(status)) {
381
0
    libnet_unjoin_set_error_string(mem_ctx, r,
382
0
      "failed to leave realm: %s",
383
0
      ads_errstr(status));
384
0
    return status;
385
0
  }
386
387
0
  return ADS_SUCCESS;
388
0
}
389
390
/****************************************************************
391
****************************************************************/
392
393
static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
394
            struct libnet_JoinCtx *r)
395
0
{
396
0
  ADS_STATUS status;
397
0
  LDAPMessage *res = NULL;
398
0
  char *dn = NULL;
399
0
  struct dom_sid sid;
400
401
0
  if (!r->in.machine_name) {
402
0
    return ADS_ERROR(LDAP_NO_MEMORY);
403
0
  }
404
405
0
  status = ads_find_machine_acct(r->in.ads,
406
0
               &res,
407
0
               r->in.machine_name);
408
0
  if (!ADS_ERR_OK(status)) {
409
0
    return status;
410
0
  }
411
412
0
  if (ads_count_replies(r->in.ads, res) != 1) {
413
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
414
0
    goto done;
415
0
  }
416
417
0
  dn = ads_get_dn(r->in.ads, mem_ctx, res);
418
0
  if (!dn) {
419
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
420
0
    goto done;
421
0
  }
422
423
0
  r->out.dn = talloc_strdup(mem_ctx, dn);
424
0
  if (!r->out.dn) {
425
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
426
0
    goto done;
427
0
  }
428
429
0
  if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
430
0
           &r->out.set_encryption_types)) {
431
0
    r->out.set_encryption_types = 0;
432
0
  }
433
434
0
  if (!ads_pull_sid(r->in.ads, res, "objectSid", &sid)) {
435
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
436
0
    goto done;
437
0
  }
438
439
0
  dom_sid_split_rid(mem_ctx, &sid, NULL, &r->out.account_rid);
440
0
 done:
441
0
  ads_msgfree(r->in.ads, res);
442
0
  TALLOC_FREE(dn);
443
444
0
  return status;
445
0
}
446
447
static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
448
                 struct libnet_JoinCtx *r,
449
                 char ***spn_array,
450
                 size_t *num_spns)
451
0
{
452
0
  ADS_STATUS status;
453
454
0
  if (r->in.machine_name == NULL) {
455
0
    return ADS_ERROR_SYSTEM(EINVAL);
456
0
  }
457
458
0
  status = ads_get_service_principal_names(mem_ctx,
459
0
             r->in.ads,
460
0
             r->in.machine_name,
461
0
             spn_array,
462
0
             num_spns);
463
464
0
  return status;
465
0
}
466
467
static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const  char *spn,
468
             const char ***array, size_t *num)
469
0
{
470
0
  bool ok = ads_element_in_array(*array, *num, spn);
471
0
  if (!ok) {
472
0
    ok = add_string_to_array(mem_ctx, spn, array, num);
473
0
    if (!ok) {
474
0
      return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
475
0
    }
476
0
  }
477
0
  return ADS_SUCCESS;
478
0
}
479
480
/****************************************************************
481
 Set a machines dNSHostName and servicePrincipalName attributes
482
****************************************************************/
483
484
static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
485
                struct libnet_JoinCtx *r)
486
0
{
487
0
  TALLOC_CTX *frame = talloc_stackframe();
488
0
  ADS_STATUS status;
489
0
  ADS_MODLIST mods;
490
0
  fstring my_fqdn;
491
0
  fstring my_alias;
492
0
  const char **spn_array = NULL;
493
0
  size_t num_spns = 0;
494
0
  char *spn = NULL;
495
0
  const char **netbios_aliases = NULL;
496
0
  const char **addl_hostnames = NULL;
497
0
  const char *dns_hostname = NULL;
498
499
  /* Find our DN */
500
501
0
  status = libnet_join_find_machine_acct(mem_ctx, r);
502
0
  if (!ADS_ERR_OK(status)) {
503
0
    goto done;
504
0
  }
505
506
0
  status = libnet_join_get_machine_spns(frame,
507
0
                r,
508
0
                discard_const_p(char **, &spn_array),
509
0
                &num_spns);
510
0
  if (!ADS_ERR_OK(status)) {
511
0
    DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
512
0
  }
513
514
  /* Windows only creates HOST/shortname & HOST/fqdn. */
515
516
0
  spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name);
517
0
  if (spn == NULL) {
518
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
519
0
    goto done;
520
0
  }
521
0
  if (!strupper_m(spn)) {
522
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
523
0
    goto done;
524
0
  }
525
526
0
  status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
527
0
  if (!ADS_ERR_OK(status)) {
528
0
    goto done;
529
0
  }
530
531
0
  if (r->in.dnshostname != NULL) {
532
0
    fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
533
0
  } else {
534
0
    fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
535
0
           lp_dnsdomain());
536
0
  }
537
538
0
  if (!strlower_m(my_fqdn)) {
539
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
540
0
    goto done;
541
0
  }
542
543
0
  spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
544
0
  if (spn == NULL) {
545
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
546
0
    goto done;
547
0
  }
548
549
0
  status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
550
0
  if (!ADS_ERR_OK(status)) {
551
0
    goto done;
552
0
  }
553
554
  /*
555
   * Register dns_hostname if needed, add_uniq_spn() will avoid
556
   * duplicates.
557
   */
558
0
  if (r->in.dnshostname != NULL) {
559
0
    dns_hostname = talloc_strdup(frame, r->in.dnshostname);
560
0
  } else {
561
0
    dns_hostname = talloc_asprintf(frame,
562
0
                 "%s.%s",
563
0
                 r->in.machine_name,
564
0
                 r->out.dns_domain_name);
565
0
  }
566
0
  if (dns_hostname == NULL) {
567
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
568
0
    goto done;
569
0
  }
570
571
0
  spn = talloc_asprintf(frame, "HOST/%s", dns_hostname);
572
0
  if (spn == NULL) {
573
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
574
0
    goto done;
575
0
  }
576
577
0
  status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
578
0
  if (!ADS_ERR_OK(status)) {
579
0
    goto done;
580
0
  }
581
582
0
  for (netbios_aliases = lp_netbios_aliases();
583
0
       netbios_aliases != NULL && *netbios_aliases != NULL;
584
0
       netbios_aliases++) {
585
    /*
586
     * Add HOST/NETBIOSNAME
587
     */
588
0
    spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases);
589
0
    if (spn == NULL) {
590
0
      status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
591
0
      goto done;
592
0
    }
593
0
    if (!strupper_m(spn)) {
594
0
      status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
595
0
      goto done;
596
0
    }
597
598
0
    status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
599
0
    if (!ADS_ERR_OK(status)) {
600
0
      goto done;
601
0
    }
602
603
    /*
604
     * Add HOST/netbiosname.domainname
605
     */
606
0
    fstr_sprintf(my_alias, "%s.%s",
607
0
           *netbios_aliases,
608
0
           lp_dnsdomain());
609
0
    if (!strlower_m(my_alias)) {
610
0
      status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
611
0
      goto done;
612
0
    }
613
614
0
    spn = talloc_asprintf(frame, "HOST/%s", my_alias);
615
0
    if (spn == NULL) {
616
0
      status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
617
0
      goto done;
618
0
    }
619
620
0
    status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
621
0
    if (!ADS_ERR_OK(status)) {
622
0
      goto done;
623
0
    }
624
0
  }
625
626
0
  for (addl_hostnames = lp_additional_dns_hostnames();
627
0
       addl_hostnames != NULL && *addl_hostnames != NULL;
628
0
       addl_hostnames++) {
629
630
0
    spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames);
631
0
    if (spn == NULL) {
632
0
      status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
633
0
      goto done;
634
0
    }
635
636
0
    status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
637
0
    if (!ADS_ERR_OK(status)) {
638
0
      goto done;
639
0
    }
640
0
  }
641
642
  /* make sure to NULL terminate the array */
643
0
  spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1);
644
0
  if (spn_array == NULL) {
645
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
646
0
    goto done;
647
0
  }
648
0
  spn_array[num_spns] = NULL;
649
650
0
  mods = ads_init_mods(mem_ctx);
651
0
  if (!mods) {
652
0
    status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
653
0
    goto done;
654
0
  }
655
656
  /* fields of primary importance */
657
658
0
  status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
659
0
  if (!ADS_ERR_OK(status)) {
660
0
    goto done;
661
0
  }
662
663
0
  status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
664
0
         spn_array);
665
0
  if (!ADS_ERR_OK(status)) {
666
0
    goto done;
667
0
  }
668
669
0
  addl_hostnames = lp_additional_dns_hostnames();
670
0
  if (addl_hostnames != NULL && *addl_hostnames != NULL) {
671
0
    status = ads_mod_strlist(mem_ctx, &mods,
672
0
           "msDS-AdditionalDnsHostName",
673
0
           addl_hostnames);
674
0
    if (!ADS_ERR_OK(status)) {
675
0
      goto done;
676
0
    }
677
0
  }
678
679
0
  status = ads_gen_mod(r->in.ads, r->out.dn, mods);
680
681
0
done:
682
0
  TALLOC_FREE(frame);
683
0
  return status;
684
0
}
685
686
/****************************************************************
687
****************************************************************/
688
689
static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
690
                struct libnet_JoinCtx *r)
691
0
{
692
0
  ADS_STATUS status;
693
0
  ADS_MODLIST mods;
694
695
0
  if (!r->in.create_upn) {
696
0
    return ADS_SUCCESS;
697
0
  }
698
699
  /* Find our DN */
700
701
0
  status = libnet_join_find_machine_acct(mem_ctx, r);
702
0
  if (!ADS_ERR_OK(status)) {
703
0
    return status;
704
0
  }
705
706
0
  if (!r->in.upn) {
707
0
    const char *realm = r->out.dns_domain_name;
708
709
    /* in case we are about to generate a keytab during the join
710
     * make sure the default upn we create is usable with kinit -k.
711
     * gd */
712
713
0
    if (USE_KERBEROS_KEYTAB) {
714
0
      realm = talloc_strdup_upper(mem_ctx,
715
0
                r->out.dns_domain_name);
716
0
    }
717
718
0
    if (!realm) {
719
0
      return ADS_ERROR(LDAP_NO_MEMORY);
720
0
    }
721
722
0
    r->in.upn = talloc_asprintf(mem_ctx,
723
0
              "host/%s@%s",
724
0
              r->in.machine_name,
725
0
              realm);
726
0
    if (!r->in.upn) {
727
0
      return ADS_ERROR(LDAP_NO_MEMORY);
728
0
    }
729
0
  }
730
731
  /* now do the mods */
732
733
0
  mods = ads_init_mods(mem_ctx);
734
0
  if (!mods) {
735
0
    return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
736
0
  }
737
738
  /* fields of primary importance */
739
740
0
  status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
741
0
  if (!ADS_ERR_OK(status)) {
742
0
    return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
743
0
  }
744
745
0
  return ads_gen_mod(r->in.ads, r->out.dn, mods);
746
0
}
747
748
749
/****************************************************************
750
****************************************************************/
751
752
static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
753
            struct libnet_JoinCtx *r)
754
0
{
755
0
  ADS_STATUS status;
756
0
  ADS_MODLIST mods;
757
0
  char *os_sp = NULL;
758
759
0
  if (!r->in.os_name || !r->in.os_version ) {
760
0
    return ADS_SUCCESS;
761
0
  }
762
763
  /* Find our DN */
764
765
0
  status = libnet_join_find_machine_acct(mem_ctx, r);
766
0
  if (!ADS_ERR_OK(status)) {
767
0
    return status;
768
0
  }
769
770
  /* now do the mods */
771
772
0
  mods = ads_init_mods(mem_ctx);
773
0
  if (!mods) {
774
0
    return ADS_ERROR(LDAP_NO_MEMORY);
775
0
  }
776
777
0
  if (r->in.os_servicepack) {
778
    /*
779
     * if blank string then leave os_sp equal to NULL to force
780
     * attribute delete (LDAP_MOD_DELETE)
781
     */
782
0
    if (!strequal(r->in.os_servicepack,"")) {
783
0
      os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
784
0
    }
785
0
  } else {
786
0
    os_sp = talloc_asprintf(mem_ctx, "Samba %s",
787
0
          samba_version_string());
788
0
  }
789
0
  if (!os_sp && !strequal(r->in.os_servicepack,"")) {
790
0
    return ADS_ERROR(LDAP_NO_MEMORY);
791
0
  }
792
793
  /* fields of primary importance */
794
795
0
  status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
796
0
           r->in.os_name);
797
0
  if (!ADS_ERR_OK(status)) {
798
0
    return status;
799
0
  }
800
801
0
  status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
802
0
           r->in.os_version);
803
0
  if (!ADS_ERR_OK(status)) {
804
0
    return status;
805
0
  }
806
807
0
  status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
808
0
           os_sp);
809
0
  if (!ADS_ERR_OK(status)) {
810
0
    return status;
811
0
  }
812
813
0
  return ads_gen_mod(r->in.ads, r->out.dn, mods);
814
0
}
815
816
/****************************************************************
817
****************************************************************/
818
819
static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
820
           struct libnet_JoinCtx *r)
821
0
{
822
0
  ADS_STATUS status;
823
0
  ADS_MODLIST mods;
824
0
  const char *etype_list_str;
825
826
0
  etype_list_str = talloc_asprintf(mem_ctx, "%d",
827
0
           r->in.desired_encryption_types);
828
0
  if (!etype_list_str) {
829
0
    return ADS_ERROR(LDAP_NO_MEMORY);
830
0
  }
831
832
  /* Find our DN */
833
834
0
  status = libnet_join_find_machine_acct(mem_ctx, r);
835
0
  if (!ADS_ERR_OK(status)) {
836
0
    return status;
837
0
  }
838
839
0
  if (r->in.desired_encryption_types == r->out.set_encryption_types) {
840
0
    return ADS_SUCCESS;
841
0
  }
842
843
  /* now do the mods */
844
845
0
  mods = ads_init_mods(mem_ctx);
846
0
  if (!mods) {
847
0
    return ADS_ERROR(LDAP_NO_MEMORY);
848
0
  }
849
850
0
  status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
851
0
           etype_list_str);
852
0
  if (!ADS_ERR_OK(status)) {
853
0
    return status;
854
0
  }
855
856
0
  status = ads_gen_mod(r->in.ads, r->out.dn, mods);
857
0
  if (!ADS_ERR_OK(status)) {
858
0
    return status;
859
0
  }
860
861
0
  r->out.set_encryption_types = r->in.desired_encryption_types;
862
863
0
  return ADS_SUCCESS;
864
0
}
865
866
/****************************************************************
867
****************************************************************/
868
869
static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
870
              struct libnet_JoinCtx *r)
871
0
{
872
0
  NTSTATUS ntstatus = sync_pw2keytabs(r->in.dc_name);
873
874
0
  return NT_STATUS_IS_OK(ntstatus);
875
0
}
876
877
/****************************************************************
878
****************************************************************/
879
880
static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
881
             struct libnet_JoinCtx *r)
882
0
{
883
0
  uint32_t domain_func;
884
0
  ADS_STATUS status;
885
0
  const char *salt = NULL;
886
0
  char *std_salt = NULL;
887
888
0
  status = ads_domain_func_level(r->in.ads, &domain_func);
889
0
  if (!ADS_ERR_OK(status)) {
890
0
    libnet_join_set_error_string(mem_ctx, r,
891
0
      "failed to determine domain functional level: %s",
892
0
      ads_errstr(status));
893
0
    return false;
894
0
  }
895
896
  /* go ahead and setup the default salt */
897
898
0
  std_salt = kerberos_standard_des_salt();
899
0
  if (!std_salt) {
900
0
    libnet_join_set_error_string(mem_ctx, r,
901
0
      "failed to obtain standard DES salt");
902
0
    return false;
903
0
  }
904
905
0
  salt = talloc_strdup(mem_ctx, std_salt);
906
0
  SAFE_FREE(std_salt);
907
0
  if (!salt) {
908
0
    return false;
909
0
  }
910
911
  /* if it's a Windows functional domain, we have to look for the UPN */
912
913
0
  if (domain_func == DS_DOMAIN_FUNCTION_2000) {
914
0
    char *upn;
915
916
0
    upn = ads_get_upn(r->in.ads, mem_ctx,
917
0
          r->in.machine_name);
918
0
    if (upn) {
919
0
      salt = talloc_strdup(mem_ctx, upn);
920
0
      if (!salt) {
921
0
        return false;
922
0
      }
923
0
    }
924
0
  }
925
926
0
  r->out.krb5_salt = salt;
927
0
  return true;
928
0
}
929
930
/****************************************************************
931
****************************************************************/
932
933
static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
934
               struct libnet_JoinCtx *r)
935
0
{
936
0
  ADS_STATUS status;
937
0
  bool need_etype_update = false;
938
939
0
  if (r->in.request_offline_join) {
940
    /*
941
     * When in the "request offline join" path we can no longer
942
     * modify the AD account as we are operating w/o network - gd
943
     */
944
0
    return ADS_SUCCESS;
945
0
  }
946
947
0
  if (!r->in.ads) {
948
0
    status = libnet_join_connect_ads_user(mem_ctx, r);
949
0
    if (!ADS_ERR_OK(status)) {
950
0
      return status;
951
0
    }
952
0
  }
953
954
0
  status = libnet_join_set_machine_spn(mem_ctx, r);
955
0
  if (!ADS_ERR_OK(status)) {
956
0
    libnet_join_set_error_string(mem_ctx, r,
957
0
      "Failed to set machine spn: %s\n"
958
0
      "Do you have sufficient permissions to create machine "
959
0
      "accounts?",
960
0
      ads_errstr(status));
961
0
    return status;
962
0
  }
963
964
0
  status = libnet_join_set_os_attributes(mem_ctx, r);
965
0
  if (!ADS_ERR_OK(status)) {
966
0
    libnet_join_set_error_string(mem_ctx, r,
967
0
      "failed to set machine os attributes: %s",
968
0
      ads_errstr(status));
969
0
    return status;
970
0
  }
971
972
0
  status = libnet_join_set_machine_upn(mem_ctx, r);
973
0
  if (!ADS_ERR_OK(status)) {
974
0
    libnet_join_set_error_string(mem_ctx, r,
975
0
      "failed to set machine upn: %s",
976
0
      ads_errstr(status));
977
0
    return status;
978
0
  }
979
980
0
  status = libnet_join_find_machine_acct(mem_ctx, r);
981
0
  if (!ADS_ERR_OK(status)) {
982
0
    return status;
983
0
  }
984
985
0
  if (r->in.desired_encryption_types != r->out.set_encryption_types) {
986
0
    uint32_t func_level = 0;
987
988
0
    status = ads_domain_func_level(r->in.ads, &func_level);
989
0
    if (!ADS_ERR_OK(status)) {
990
0
      libnet_join_set_error_string(mem_ctx, r,
991
0
        "failed to query domain controller functional level: %s",
992
0
        ads_errstr(status));
993
0
      return status;
994
0
    }
995
996
0
    if (func_level >= DS_DOMAIN_FUNCTION_2008) {
997
0
      need_etype_update = true;
998
0
    }
999
0
  }
1000
1001
0
  if (need_etype_update) {
1002
    /*
1003
     * We need to reconnect as machine account in order
1004
     * to update msDS-SupportedEncryptionTypes reliable
1005
     */
1006
1007
0
    TALLOC_FREE(r->in.ads);
1008
1009
0
    status = libnet_join_connect_ads_machine(mem_ctx, r);
1010
0
    if (!ADS_ERR_OK(status)) {
1011
0
      libnet_join_set_error_string(mem_ctx, r,
1012
0
        "Failed to connect as machine account: %s",
1013
0
        ads_errstr(status));
1014
0
      return status;
1015
0
    }
1016
1017
0
    status = libnet_join_set_etypes(mem_ctx, r);
1018
0
    if (!ADS_ERR_OK(status)) {
1019
0
      libnet_join_set_error_string(mem_ctx, r,
1020
0
        "failed to set machine kerberos encryption types: %s",
1021
0
        ads_errstr(status));
1022
0
      return status;
1023
0
    }
1024
0
  }
1025
1026
0
  if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1027
0
    return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1028
0
  }
1029
1030
0
  return ADS_SUCCESS;
1031
0
}
1032
1033
static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
1034
              struct libnet_JoinCtx *r)
1035
0
{
1036
0
  if (!libnet_join_create_keytab(mem_ctx, r)) {
1037
0
    libnet_join_set_error_string(mem_ctx, r,
1038
0
      "failed to create kerberos keytab");
1039
0
    return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1040
0
  }
1041
1042
0
  return ADS_SUCCESS;
1043
0
}
1044
#endif /* HAVE_ADS */
1045
1046
/****************************************************************
1047
 Store the machine password and domain SID
1048
****************************************************************/
1049
1050
static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1051
             struct libnet_JoinCtx *r)
1052
0
{
1053
0
  NTSTATUS status;
1054
1055
0
  status = secrets_store_JoinCtx(r);
1056
0
  if (!NT_STATUS_IS_OK(status)) {
1057
0
    DBG_ERR("secrets_store_JoinCtx() failed %s\n",
1058
0
      nt_errstr(status));
1059
0
    return false;
1060
0
  }
1061
1062
0
  return true;
1063
0
}
1064
1065
/****************************************************************
1066
 Connect dc's IPC$ share
1067
****************************************************************/
1068
1069
static NTSTATUS libnet_join_connect_dc_ipc(TALLOC_CTX *mem_ctx,
1070
             const char *dc,
1071
             struct cli_credentials *creds,
1072
             struct cli_state **cli)
1073
0
{
1074
0
  int flags = CLI_FULL_CONNECTION_IPC;
1075
0
  struct smb_transports ts =
1076
0
    smb_transports_parse("client smb transports",
1077
0
             lp_client_smb_transports());
1078
0
  NTSTATUS status;
1079
1080
0
  status = cli_full_connection_creds(mem_ctx,
1081
0
             cli,
1082
0
             NULL,
1083
0
             dc,
1084
0
             NULL,
1085
0
             &ts,
1086
0
             "IPC$", "IPC",
1087
0
             creds,
1088
0
             flags);
1089
0
  if (!NT_STATUS_IS_OK(status)) {
1090
0
    return status;
1091
0
  }
1092
1093
0
  return NT_STATUS_OK;
1094
0
}
1095
1096
/****************************************************************
1097
 Lookup domain dc's info
1098
****************************************************************/
1099
1100
static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1101
            struct libnet_JoinCtx *r,
1102
            struct cli_state **cli)
1103
0
{
1104
0
  TALLOC_CTX *frame = talloc_stackframe();
1105
0
  struct rpc_pipe_client *pipe_hnd = NULL;
1106
0
  struct policy_handle lsa_pol;
1107
0
  NTSTATUS status, result;
1108
0
  union lsa_PolicyInformation *info = NULL;
1109
0
  struct cli_credentials *creds = NULL;
1110
0
  struct dcerpc_binding_handle *b;
1111
1112
0
  if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1113
0
    creds = cli_credentials_init_anon(frame);
1114
0
    if (creds == NULL) {
1115
0
      status = NT_STATUS_NO_MEMORY;
1116
0
      goto done;
1117
0
    }
1118
0
  } else {
1119
0
    creds = r->in.admin_credentials;
1120
0
  }
1121
1122
0
  status = libnet_join_connect_dc_ipc(mem_ctx,
1123
0
              r->in.dc_name,
1124
0
              creds,
1125
0
              cli);
1126
0
  if (!NT_STATUS_IS_OK(status)) {
1127
0
    goto done;
1128
0
  }
1129
1130
0
  status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1131
0
            &pipe_hnd);
1132
0
  if (!NT_STATUS_IS_OK(status)) {
1133
0
    DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1134
0
      nt_errstr(status)));
1135
0
    goto done;
1136
0
  }
1137
1138
0
  b = pipe_hnd->binding_handle;
1139
1140
0
  status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1141
0
          SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1142
0
  if (!NT_STATUS_IS_OK(status)) {
1143
0
    goto done;
1144
0
  }
1145
1146
0
  status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1147
0
               &lsa_pol,
1148
0
               LSA_POLICY_INFO_DNS,
1149
0
               &info,
1150
0
               &result);
1151
0
  if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1152
0
    r->out.domain_is_ad = true;
1153
0
    r->out.netbios_domain_name = info->dns.name.string;
1154
0
    r->out.dns_domain_name = info->dns.dns_domain.string;
1155
0
    r->out.forest_name = info->dns.dns_forest.string;
1156
0
    r->out.domain_guid = info->dns.domain_guid;
1157
0
    r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1158
0
    NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1159
0
  }
1160
1161
0
  if (!NT_STATUS_IS_OK(status)) {
1162
0
    status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1163
0
                &lsa_pol,
1164
0
                LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1165
0
                &info,
1166
0
                &result);
1167
0
    if (!NT_STATUS_IS_OK(status)) {
1168
0
      goto done;
1169
0
    }
1170
0
    if (!NT_STATUS_IS_OK(result)) {
1171
0
      status = result;
1172
0
      goto done;
1173
0
    }
1174
1175
0
    r->out.netbios_domain_name = info->account_domain.name.string;
1176
0
    r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1177
0
    NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1178
0
  }
1179
1180
0
  dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1181
0
  TALLOC_FREE(pipe_hnd);
1182
1183
0
 done:
1184
0
  TALLOC_FREE(frame);
1185
0
  return status;
1186
0
}
1187
1188
/****************************************************************
1189
 Do the domain join unsecure
1190
****************************************************************/
1191
1192
static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1193
                struct libnet_JoinCtx *r,
1194
                struct cli_state *cli)
1195
0
{
1196
0
  TALLOC_CTX *frame = talloc_stackframe();
1197
0
  struct rpc_pipe_client *passwordset_pipe = NULL;
1198
0
  struct cli_credentials *cli_creds;
1199
0
  struct netlogon_creds_cli_context *netlogon_creds = NULL;
1200
0
  const struct sockaddr_storage *remote_sockaddr = NULL;
1201
0
  size_t len = 0;
1202
0
  bool ok;
1203
0
  DATA_BLOB new_trust_blob = data_blob_null;
1204
0
  NTSTATUS status;
1205
1206
0
  if (!r->in.machine_password) {
1207
0
    int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1208
1209
0
    r->in.machine_password = trust_pw_new_value(mem_ctx,
1210
0
            r->in.secure_channel_type,
1211
0
            security);
1212
0
    if (r->in.machine_password == NULL) {
1213
0
      TALLOC_FREE(frame);
1214
0
      return NT_STATUS_NO_MEMORY;
1215
0
    }
1216
0
  }
1217
1218
0
  cli_creds = cli_credentials_init(talloc_tos());
1219
0
  if (cli_creds == NULL) {
1220
0
    TALLOC_FREE(frame);
1221
0
    return NT_STATUS_NO_MEMORY;
1222
0
  }
1223
1224
0
  cli_credentials_set_username(cli_creds, r->out.account_name,
1225
0
             CRED_SPECIFIED);
1226
0
  cli_credentials_set_domain(cli_creds, r->in.domain_name,
1227
0
           CRED_SPECIFIED);
1228
0
  cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1229
0
  cli_credentials_set_secure_channel_type(cli_creds,
1230
0
            r->in.secure_channel_type);
1231
1232
  /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1233
0
  cli_credentials_set_password(cli_creds,
1234
0
             r->in.passed_machine_password,
1235
0
             CRED_SPECIFIED);
1236
1237
0
  cli_credentials_add_gensec_features(cli_creds,
1238
0
              GENSEC_FEATURE_NO_DELEGATION,
1239
0
              CRED_SPECIFIED);
1240
1241
0
  remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
1242
1243
0
  status = rpccli_create_netlogon_creds_ctx(cli_creds,
1244
0
              r->in.dc_name,
1245
0
              r->in.msg_ctx,
1246
0
              frame,
1247
0
              &netlogon_creds);
1248
0
  if (!NT_STATUS_IS_OK(status)) {
1249
0
    TALLOC_FREE(frame);
1250
0
    return status;
1251
0
  }
1252
1253
0
  status = rpccli_connect_netlogon(cli,
1254
0
           NCACN_NP,
1255
0
           r->in.dc_name,
1256
0
           remote_sockaddr,
1257
0
           netlogon_creds,
1258
0
           true, /* force_reauth */
1259
0
           cli_creds,
1260
0
           &passwordset_pipe);
1261
0
  if (!NT_STATUS_IS_OK(status)) {
1262
0
    TALLOC_FREE(frame);
1263
0
    return status;
1264
0
  }
1265
1266
0
  len = strlen(r->in.machine_password);
1267
0
  ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1268
0
           r->in.machine_password, len,
1269
0
           &new_trust_blob.data,
1270
0
           &new_trust_blob.length);
1271
0
  if (!ok) {
1272
0
    status = NT_STATUS_UNMAPPABLE_CHARACTER;
1273
0
    if (errno == ENOMEM) {
1274
0
      status = NT_STATUS_NO_MEMORY;
1275
0
    }
1276
0
    TALLOC_FREE(frame);
1277
0
    return status;
1278
0
  }
1279
1280
0
  status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1281
0
                  passwordset_pipe->binding_handle,
1282
0
                  &new_trust_blob,
1283
0
                  NULL); /* new_version */
1284
0
  if (!NT_STATUS_IS_OK(status)) {
1285
0
    TALLOC_FREE(frame);
1286
0
    return status;
1287
0
  }
1288
1289
0
  TALLOC_FREE(frame);
1290
0
  return NT_STATUS_OK;
1291
0
}
1292
1293
/****************************************************************
1294
 Do the domain join
1295
****************************************************************/
1296
1297
static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1298
             struct libnet_JoinCtx *r,
1299
             struct cli_state *cli)
1300
0
{
1301
0
  struct rpc_pipe_client *pipe_hnd = NULL;
1302
0
  struct policy_handle sam_pol, domain_pol, user_pol;
1303
0
  NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1304
0
  char *acct_name;
1305
0
  struct lsa_String lsa_acct_name;
1306
0
  uint32_t acct_flags = ACB_WSTRUST;
1307
0
  struct samr_Ids user_rids;
1308
0
  struct samr_Ids name_types;
1309
0
  union samr_UserInfo user_info;
1310
0
  struct dcerpc_binding_handle *b = NULL;
1311
0
  unsigned int old_timeout = 0;
1312
1313
0
  DATA_BLOB session_key = data_blob_null;
1314
0
  struct samr_CryptPassword crypt_pwd;
1315
0
  struct samr_CryptPasswordEx crypt_pwd_ex;
1316
1317
0
  ZERO_STRUCT(sam_pol);
1318
0
  ZERO_STRUCT(domain_pol);
1319
0
  ZERO_STRUCT(user_pol);
1320
1321
0
  switch (r->in.secure_channel_type) {
1322
0
  case SEC_CHAN_WKSTA:
1323
0
    acct_flags = ACB_WSTRUST;
1324
0
    break;
1325
0
  case SEC_CHAN_BDC:
1326
0
    acct_flags = ACB_SVRTRUST;
1327
0
    break;
1328
0
  default:
1329
0
    return NT_STATUS_INVALID_PARAMETER;
1330
0
  }
1331
1332
0
  if (!r->in.machine_password) {
1333
0
    int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1334
1335
0
    r->in.machine_password = trust_pw_new_value(mem_ctx,
1336
0
            r->in.secure_channel_type,
1337
0
            security);
1338
0
    NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1339
0
  }
1340
1341
  /* Open the domain */
1342
1343
0
  status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1344
0
            &pipe_hnd);
1345
0
  if (!NT_STATUS_IS_OK(status)) {
1346
0
    DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1347
0
      nt_errstr(status)));
1348
0
    goto done;
1349
0
  }
1350
1351
0
  b = pipe_hnd->binding_handle;
1352
1353
0
  status = dcerpc_binding_handle_transport_session_key(
1354
0
        b, mem_ctx, &session_key);
1355
0
  if (!NT_STATUS_IS_OK(status)) {
1356
0
    DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1357
0
      nt_errstr(status)));
1358
0
    goto done;
1359
0
  }
1360
1361
0
  status = dcerpc_samr_Connect2(b, mem_ctx,
1362
0
              pipe_hnd->desthost,
1363
0
              SAMR_ACCESS_ENUM_DOMAINS
1364
0
              | SAMR_ACCESS_LOOKUP_DOMAIN,
1365
0
              &sam_pol,
1366
0
              &result);
1367
0
  if (!NT_STATUS_IS_OK(status)) {
1368
0
    goto done;
1369
0
  }
1370
0
  if (!NT_STATUS_IS_OK(result)) {
1371
0
    status = result;
1372
0
    goto done;
1373
0
  }
1374
1375
0
  status = dcerpc_samr_OpenDomain(b, mem_ctx,
1376
0
          &sam_pol,
1377
0
          SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1378
0
          | SAMR_DOMAIN_ACCESS_CREATE_USER
1379
0
          | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1380
0
          r->out.domain_sid,
1381
0
          &domain_pol,
1382
0
          &result);
1383
0
  if (!NT_STATUS_IS_OK(status)) {
1384
0
    goto done;
1385
0
  }
1386
0
  if (!NT_STATUS_IS_OK(result)) {
1387
0
    status = result;
1388
0
    goto done;
1389
0
  }
1390
1391
  /* Create domain user */
1392
1393
0
  acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1394
0
  if (!strlower_m(acct_name)) {
1395
0
    status = NT_STATUS_INVALID_PARAMETER;
1396
0
    goto done;
1397
0
  }
1398
1399
0
  init_lsa_String(&lsa_acct_name, acct_name);
1400
1401
0
  if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1402
0
    uint32_t access_desired =
1403
0
      SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1404
0
      SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1405
0
      SAMR_USER_ACCESS_SET_PASSWORD |
1406
0
      SAMR_USER_ACCESS_GET_ATTRIBUTES |
1407
0
      SAMR_USER_ACCESS_SET_ATTRIBUTES;
1408
0
    uint32_t access_granted = 0;
1409
1410
0
    DEBUG(10,("Creating account with desired access mask: %d\n",
1411
0
      access_desired));
1412
1413
0
    status = dcerpc_samr_CreateUser2(b, mem_ctx,
1414
0
             &domain_pol,
1415
0
             &lsa_acct_name,
1416
0
             acct_flags,
1417
0
             access_desired,
1418
0
             &user_pol,
1419
0
             &access_granted,
1420
0
             &r->out.account_rid,
1421
0
             &result);
1422
0
    if (!NT_STATUS_IS_OK(status)) {
1423
0
      goto done;
1424
0
    }
1425
1426
0
    status = result;
1427
0
    if (!NT_STATUS_IS_OK(status) &&
1428
0
        !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1429
1430
0
      DEBUG(10,("Creation of workstation account failed: %s\n",
1431
0
        nt_errstr(status)));
1432
1433
      /* If NT_STATUS_ACCESS_DENIED then we have a valid
1434
         username/password combo but the user does not have
1435
         administrator access. */
1436
1437
0
      if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1438
0
        libnet_join_set_error_string(mem_ctx, r,
1439
0
          "User specified does not have "
1440
0
          "administrator privileges");
1441
0
      }
1442
1443
0
      goto done;
1444
0
    }
1445
1446
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1447
0
      if (!(r->in.join_flags &
1448
0
            WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1449
0
        goto done;
1450
0
      }
1451
0
    }
1452
1453
    /* We *must* do this.... don't ask... */
1454
1455
0
    if (NT_STATUS_IS_OK(status)) {
1456
0
      dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1457
0
    }
1458
0
  }
1459
1460
0
  status = dcerpc_samr_LookupNames(b, mem_ctx,
1461
0
           &domain_pol,
1462
0
           1,
1463
0
           &lsa_acct_name,
1464
0
           &user_rids,
1465
0
           &name_types,
1466
0
           &result);
1467
0
  if (!NT_STATUS_IS_OK(status)) {
1468
0
    goto done;
1469
0
  }
1470
0
  if (!NT_STATUS_IS_OK(result)) {
1471
0
    status = result;
1472
0
    goto done;
1473
0
  }
1474
0
  if (user_rids.count != 1) {
1475
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1476
0
    goto done;
1477
0
  }
1478
0
  if (name_types.count != 1) {
1479
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1480
0
    goto done;
1481
0
  }
1482
1483
0
  if (name_types.ids[0] != SID_NAME_USER) {
1484
0
    DEBUG(0,("%s is not a user account (type=%d)\n",
1485
0
      acct_name, name_types.ids[0]));
1486
0
    status = NT_STATUS_INVALID_WORKSTATION;
1487
0
    goto done;
1488
0
  }
1489
1490
0
  r->out.account_rid = user_rids.ids[0];
1491
1492
  /* Open handle on user */
1493
1494
0
  status = dcerpc_samr_OpenUser(b, mem_ctx,
1495
0
              &domain_pol,
1496
0
              SEC_FLAG_MAXIMUM_ALLOWED,
1497
0
              r->out.account_rid,
1498
0
              &user_pol,
1499
0
              &result);
1500
0
  if (!NT_STATUS_IS_OK(status)) {
1501
0
    goto done;
1502
0
  }
1503
0
  if (!NT_STATUS_IS_OK(result)) {
1504
0
    status = result;
1505
0
    goto done;
1506
0
  }
1507
1508
  /* Fill in the additional account flags now */
1509
1510
0
  acct_flags |= ACB_PWNOEXP;
1511
1512
  /* Set account flags on machine account */
1513
0
  ZERO_STRUCT(user_info.info16);
1514
0
  user_info.info16.acct_flags = acct_flags;
1515
1516
0
  status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1517
0
            &user_pol,
1518
0
            UserControlInformation,
1519
0
            &user_info,
1520
0
            &result);
1521
0
  if (!NT_STATUS_IS_OK(status)) {
1522
0
    dcerpc_samr_DeleteUser(b, mem_ctx,
1523
0
               &user_pol,
1524
0
               &result);
1525
1526
0
    libnet_join_set_error_string(mem_ctx, r,
1527
0
      "Failed to set account flags for machine account (%s)\n",
1528
0
      nt_errstr(status));
1529
0
    goto done;
1530
0
  }
1531
1532
0
  if (!NT_STATUS_IS_OK(result)) {
1533
0
    status = result;
1534
1535
0
    dcerpc_samr_DeleteUser(b, mem_ctx,
1536
0
               &user_pol,
1537
0
               &result);
1538
1539
0
    libnet_join_set_error_string(mem_ctx, r,
1540
0
      "Failed to set account flags for machine account (%s)\n",
1541
0
      nt_errstr(status));
1542
0
    goto done;
1543
0
  }
1544
1545
  /* Set password on machine account - first try level 26 */
1546
1547
  /*
1548
   * increase the timeout as password filter modules on the DC
1549
   * might delay the operation for a significant amount of time
1550
   */
1551
0
  old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1552
1553
0
  status = init_samr_CryptPasswordEx(r->in.machine_password,
1554
0
             &session_key,
1555
0
             &crypt_pwd_ex);
1556
0
  if (!NT_STATUS_IS_OK(status)) {
1557
0
    goto error;
1558
0
  }
1559
1560
0
  user_info.info26.password = crypt_pwd_ex;
1561
0
  user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1562
1563
0
  status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1564
0
            &user_pol,
1565
0
            UserInternal5InformationNew,
1566
0
            &user_info,
1567
0
            &result);
1568
1569
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1570
1571
    /* retry with level 24 */
1572
1573
0
    status = init_samr_CryptPassword(r->in.machine_password,
1574
0
             &session_key,
1575
0
             &crypt_pwd);
1576
0
    if (!NT_STATUS_IS_OK(status)) {
1577
0
      goto error;
1578
0
    }
1579
1580
0
    user_info.info24.password = crypt_pwd;
1581
0
    user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1582
1583
0
    status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1584
0
              &user_pol,
1585
0
              UserInternal5Information,
1586
0
              &user_info,
1587
0
              &result);
1588
0
  }
1589
1590
0
error:
1591
0
  old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1592
1593
0
  if (!NT_STATUS_IS_OK(status)) {
1594
1595
0
    dcerpc_samr_DeleteUser(b, mem_ctx,
1596
0
               &user_pol,
1597
0
               &result);
1598
1599
0
    libnet_join_set_error_string(mem_ctx, r,
1600
0
      "Failed to set password for machine account (%s)\n",
1601
0
      nt_errstr(status));
1602
0
    goto done;
1603
0
  }
1604
0
  if (!NT_STATUS_IS_OK(result)) {
1605
0
    status = result;
1606
1607
0
    dcerpc_samr_DeleteUser(b, mem_ctx,
1608
0
               &user_pol,
1609
0
               &result);
1610
1611
0
    libnet_join_set_error_string(mem_ctx, r,
1612
0
      "Failed to set password for machine account (%s)\n",
1613
0
      nt_errstr(status));
1614
0
    goto done;
1615
0
  }
1616
1617
0
  status = NT_STATUS_OK;
1618
1619
0
 done:
1620
0
  if (!pipe_hnd) {
1621
0
    return status;
1622
0
  }
1623
1624
0
  data_blob_clear_free(&session_key);
1625
1626
0
  if (is_valid_policy_hnd(&sam_pol)) {
1627
0
    dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1628
0
  }
1629
0
  if (is_valid_policy_hnd(&domain_pol)) {
1630
0
    dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1631
0
  }
1632
0
  if (is_valid_policy_hnd(&user_pol)) {
1633
0
    dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1634
0
  }
1635
0
  TALLOC_FREE(pipe_hnd);
1636
1637
0
  return status;
1638
0
}
1639
1640
/****************************************************************
1641
****************************************************************/
1642
1643
NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1644
      const char *netbios_domain_name,
1645
      const char *dc_name,
1646
      enum credentials_use_kerberos kerberos_state)
1647
0
{
1648
0
  TALLOC_CTX *frame = talloc_stackframe();
1649
0
  struct cli_state *cli = NULL;
1650
0
  struct rpc_pipe_client *netlogon_pipe = NULL;
1651
0
  struct cli_credentials *cli_creds = NULL;
1652
0
  struct netlogon_creds_cli_context *netlogon_creds = NULL;
1653
0
  NTSTATUS status;
1654
0
  int flags = CLI_FULL_CONNECTION_IPC;
1655
0
  const struct sockaddr_storage *remote_sockaddr = NULL;
1656
0
  struct smb_transports ts =
1657
0
    smb_transports_parse("client smb transports",
1658
0
             lp_client_smb_transports());
1659
1660
0
  if (!dc_name) {
1661
0
    TALLOC_FREE(frame);
1662
0
    return NT_STATUS_INVALID_PARAMETER;
1663
0
  }
1664
1665
0
  if (!secrets_init()) {
1666
0
    TALLOC_FREE(frame);
1667
0
    return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1668
0
  }
1669
1670
0
  status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1671
0
             frame, &cli_creds);
1672
0
  if (!NT_STATUS_IS_OK(status)) {
1673
0
    TALLOC_FREE(frame);
1674
0
    return status;
1675
0
  }
1676
1677
  /* we don't want any old password */
1678
0
  cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1679
1680
0
  cli_credentials_set_kerberos_state(cli_creds,
1681
0
             kerberos_state,
1682
0
             CRED_SPECIFIED);
1683
1684
0
  cli_credentials_add_gensec_features(cli_creds,
1685
0
              GENSEC_FEATURE_NO_DELEGATION,
1686
0
              CRED_SPECIFIED);
1687
1688
0
  status = cli_full_connection_creds(frame,
1689
0
             &cli,
1690
0
             NULL,
1691
0
             dc_name,
1692
0
             NULL,
1693
0
             &ts,
1694
0
             "IPC$", "IPC",
1695
0
             cli_creds,
1696
0
             flags);
1697
1698
0
  if (!NT_STATUS_IS_OK(status)) {
1699
0
    struct cli_credentials *anon_creds = NULL;
1700
1701
0
    anon_creds = cli_credentials_init_anon(frame);
1702
0
    if (anon_creds == NULL) {
1703
0
      TALLOC_FREE(frame);
1704
0
      return NT_STATUS_NO_MEMORY;
1705
0
    }
1706
1707
0
    status = cli_full_connection_creds(frame,
1708
0
               &cli,
1709
0
               NULL,
1710
0
               dc_name,
1711
0
               NULL,
1712
0
               &ts,
1713
0
               "IPC$", "IPC",
1714
0
               anon_creds,
1715
0
               flags);
1716
0
  }
1717
1718
0
  if (!NT_STATUS_IS_OK(status)) {
1719
0
    TALLOC_FREE(frame);
1720
0
    return status;
1721
0
  }
1722
1723
0
  remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
1724
1725
0
  status = rpccli_create_netlogon_creds_ctx(cli_creds,
1726
0
              dc_name,
1727
0
              msg_ctx,
1728
0
              frame,
1729
0
              &netlogon_creds);
1730
0
  if (!NT_STATUS_IS_OK(status)) {
1731
0
    cli_shutdown(cli);
1732
0
    TALLOC_FREE(frame);
1733
0
    return status;
1734
0
  }
1735
1736
0
  status = rpccli_connect_netlogon(cli,
1737
0
           NCACN_NP,
1738
0
           dc_name,
1739
0
           remote_sockaddr,
1740
0
           netlogon_creds,
1741
0
           true, /* force_reauth */
1742
0
           cli_creds,
1743
0
           &netlogon_pipe);
1744
0
  if (!NT_STATUS_IS_OK(status)) {
1745
0
    DBG_ERR("failed to open schannel session "
1746
0
      "on netlogon pipe to server %s for domain %s. "
1747
0
      "Error was %s\n",
1748
0
      dc_name, netbios_domain_name, nt_errstr(status));
1749
0
    cli_shutdown(cli);
1750
0
    TALLOC_FREE(frame);
1751
0
    return status;
1752
0
  }
1753
1754
0
  TALLOC_FREE(netlogon_pipe);
1755
1756
0
  cli_shutdown(cli);
1757
0
  TALLOC_FREE(frame);
1758
0
  return NT_STATUS_OK;
1759
0
}
1760
1761
/****************************************************************
1762
****************************************************************/
1763
1764
static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1765
              struct libnet_JoinCtx *r)
1766
0
{
1767
0
  NTSTATUS status;
1768
0
  enum credentials_use_kerberos kerberos_state = CRED_USE_KERBEROS_DESIRED;
1769
1770
0
  if (r->in.admin_credentials != NULL) {
1771
0
    kerberos_state = cli_credentials_get_kerberos_state(
1772
0
          r->in.admin_credentials);
1773
0
  }
1774
1775
0
  status = libnet_join_ok(r->in.msg_ctx,
1776
0
        r->out.netbios_domain_name,
1777
0
        r->in.dc_name,
1778
0
        kerberos_state);
1779
0
  if (!NT_STATUS_IS_OK(status)) {
1780
0
    libnet_join_set_error_string(mem_ctx, r,
1781
0
      "failed to verify domain membership after joining: %s",
1782
0
      get_friendly_nt_error_msg(status));
1783
0
    return WERR_NERR_SETUPNOTJOINED;
1784
0
  }
1785
1786
0
  return WERR_OK;
1787
0
}
1788
1789
/****************************************************************
1790
****************************************************************/
1791
1792
static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1793
                struct libnet_UnjoinCtx *r)
1794
0
{
1795
  /*
1796
   * TODO: use values from 'struct libnet_UnjoinCtx' ?
1797
   */
1798
0
  return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1799
0
}
1800
1801
/****************************************************************
1802
****************************************************************/
1803
1804
static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1805
               struct libnet_UnjoinCtx *r)
1806
0
{
1807
0
  struct cli_state *cli = NULL;
1808
0
  struct rpc_pipe_client *pipe_hnd = NULL;
1809
0
  struct policy_handle sam_pol, domain_pol, user_pol;
1810
0
  NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1811
0
  char *acct_name;
1812
0
  uint32_t user_rid;
1813
0
  struct lsa_String lsa_acct_name;
1814
0
  struct samr_Ids user_rids;
1815
0
  struct samr_Ids name_types;
1816
0
  union samr_UserInfo *info = NULL;
1817
0
  struct dcerpc_binding_handle *b = NULL;
1818
1819
0
  ZERO_STRUCT(sam_pol);
1820
0
  ZERO_STRUCT(domain_pol);
1821
0
  ZERO_STRUCT(user_pol);
1822
1823
0
  status = libnet_join_connect_dc_ipc(mem_ctx,
1824
0
              r->in.dc_name,
1825
0
              r->in.admin_credentials,
1826
0
              &cli);
1827
0
  if (!NT_STATUS_IS_OK(status)) {
1828
0
    goto done;
1829
0
  }
1830
1831
  /* Open the domain */
1832
1833
0
  status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1834
0
            &pipe_hnd);
1835
0
  if (!NT_STATUS_IS_OK(status)) {
1836
0
    DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1837
0
      nt_errstr(status)));
1838
0
    goto done;
1839
0
  }
1840
1841
0
  b = pipe_hnd->binding_handle;
1842
1843
0
  status = dcerpc_samr_Connect2(b, mem_ctx,
1844
0
              pipe_hnd->desthost,
1845
0
              SEC_FLAG_MAXIMUM_ALLOWED,
1846
0
              &sam_pol,
1847
0
              &result);
1848
0
  if (!NT_STATUS_IS_OK(status)) {
1849
0
    goto done;
1850
0
  }
1851
0
  if (!NT_STATUS_IS_OK(result)) {
1852
0
    status = result;
1853
0
    goto done;
1854
0
  }
1855
1856
0
  status = dcerpc_samr_OpenDomain(b, mem_ctx,
1857
0
          &sam_pol,
1858
0
          SEC_FLAG_MAXIMUM_ALLOWED,
1859
0
          r->in.domain_sid,
1860
0
          &domain_pol,
1861
0
          &result);
1862
0
  if (!NT_STATUS_IS_OK(status)) {
1863
0
    goto done;
1864
0
  }
1865
0
  if (!NT_STATUS_IS_OK(result)) {
1866
0
    status = result;
1867
0
    goto done;
1868
0
  }
1869
1870
  /* Create domain user */
1871
1872
0
  acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1873
0
  if (!strlower_m(acct_name)) {
1874
0
    status = NT_STATUS_INVALID_PARAMETER;
1875
0
    goto done;
1876
0
  }
1877
1878
0
  init_lsa_String(&lsa_acct_name, acct_name);
1879
1880
0
  status = dcerpc_samr_LookupNames(b, mem_ctx,
1881
0
           &domain_pol,
1882
0
           1,
1883
0
           &lsa_acct_name,
1884
0
           &user_rids,
1885
0
           &name_types,
1886
0
           &result);
1887
1888
0
  if (!NT_STATUS_IS_OK(status)) {
1889
0
    goto done;
1890
0
  }
1891
0
  if (!NT_STATUS_IS_OK(result)) {
1892
0
    status = result;
1893
0
    goto done;
1894
0
  }
1895
0
  if (user_rids.count != 1) {
1896
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1897
0
    goto done;
1898
0
  }
1899
0
  if (name_types.count != 1) {
1900
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1901
0
    goto done;
1902
0
  }
1903
1904
0
  if (name_types.ids[0] != SID_NAME_USER) {
1905
0
    DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1906
0
      name_types.ids[0]));
1907
0
    status = NT_STATUS_INVALID_WORKSTATION;
1908
0
    goto done;
1909
0
  }
1910
1911
0
  user_rid = user_rids.ids[0];
1912
1913
  /* Open handle on user */
1914
1915
0
  status = dcerpc_samr_OpenUser(b, mem_ctx,
1916
0
              &domain_pol,
1917
0
              SEC_FLAG_MAXIMUM_ALLOWED,
1918
0
              user_rid,
1919
0
              &user_pol,
1920
0
              &result);
1921
0
  if (!NT_STATUS_IS_OK(status)) {
1922
0
    goto done;
1923
0
  }
1924
0
  if (!NT_STATUS_IS_OK(result)) {
1925
0
    status = result;
1926
0
    goto done;
1927
0
  }
1928
1929
  /* Get user info */
1930
1931
0
  status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1932
0
             &user_pol,
1933
0
             16,
1934
0
             &info,
1935
0
             &result);
1936
0
  if (!NT_STATUS_IS_OK(status)) {
1937
0
    dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1938
0
    goto done;
1939
0
  }
1940
0
  if (!NT_STATUS_IS_OK(result)) {
1941
0
    status = result;
1942
0
    dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1943
0
    goto done;
1944
0
  }
1945
1946
  /* now disable and setuser info */
1947
1948
0
  info->info16.acct_flags |= ACB_DISABLED;
1949
1950
0
  status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1951
0
           &user_pol,
1952
0
           16,
1953
0
           info,
1954
0
           &result);
1955
0
  if (!NT_STATUS_IS_OK(status)) {
1956
0
    dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1957
0
    goto done;
1958
0
  }
1959
0
  if (!NT_STATUS_IS_OK(result)) {
1960
0
    status = result;
1961
0
    dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1962
0
    goto done;
1963
0
  }
1964
0
  status = result;
1965
0
  dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1966
1967
0
done:
1968
0
  if (pipe_hnd && b) {
1969
0
    if (is_valid_policy_hnd(&domain_pol)) {
1970
0
      dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1971
0
    }
1972
0
    if (is_valid_policy_hnd(&sam_pol)) {
1973
0
      dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1974
0
    }
1975
0
    TALLOC_FREE(pipe_hnd);
1976
0
  }
1977
1978
0
  if (cli) {
1979
0
    cli_shutdown(cli);
1980
0
  }
1981
1982
0
  return status;
1983
0
}
1984
1985
/****************************************************************
1986
****************************************************************/
1987
1988
static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1989
0
{
1990
0
  WERROR werr = WERR_OK;
1991
0
  sbcErr err;
1992
0
  struct smbconf_ctx *ctx;
1993
1994
0
  err = smbconf_init_reg(r, &ctx, NULL);
1995
0
  if (!SBC_ERROR_IS_OK(err)) {
1996
0
    werr = WERR_SERVICE_DOES_NOT_EXIST;
1997
0
    goto done;
1998
0
  }
1999
2000
0
  err = smbconf_set_global_parameter(ctx, "netbios name",
2001
0
             r->in.machine_name);
2002
0
  if (!SBC_ERROR_IS_OK(err)) {
2003
0
    werr = WERR_SERVICE_DOES_NOT_EXIST;
2004
0
    goto done;
2005
0
  }
2006
2007
0
  if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2008
2009
0
    err = smbconf_set_global_parameter(ctx, "security", "user");
2010
0
    if (!SBC_ERROR_IS_OK(err)) {
2011
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2012
0
      goto done;
2013
0
    }
2014
2015
0
    err = smbconf_set_global_parameter(ctx, "workgroup",
2016
0
               r->in.domain_name);
2017
0
    if (!SBC_ERROR_IS_OK(err)) {
2018
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2019
0
      goto done;
2020
0
    }
2021
2022
0
    smbconf_delete_global_parameter(ctx, "realm");
2023
0
    goto done;
2024
0
  }
2025
2026
0
  err = smbconf_set_global_parameter(ctx, "security", "domain");
2027
0
  if (!SBC_ERROR_IS_OK(err)) {
2028
0
    werr = WERR_SERVICE_DOES_NOT_EXIST;
2029
0
    goto done;
2030
0
  }
2031
2032
0
  err = smbconf_set_global_parameter(ctx, "workgroup",
2033
0
             r->out.netbios_domain_name);
2034
0
  if (!SBC_ERROR_IS_OK(err)) {
2035
0
    werr = WERR_SERVICE_DOES_NOT_EXIST;
2036
0
    goto done;
2037
0
  }
2038
2039
0
  if (r->out.domain_is_ad) {
2040
0
    err = smbconf_set_global_parameter(ctx, "security", "ads");
2041
0
    if (!SBC_ERROR_IS_OK(err)) {
2042
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2043
0
      goto done;
2044
0
    }
2045
2046
0
    err = smbconf_set_global_parameter(ctx, "realm",
2047
0
               r->out.dns_domain_name);
2048
0
    if (!SBC_ERROR_IS_OK(err)) {
2049
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2050
0
      goto done;
2051
0
    }
2052
0
  }
2053
2054
0
 done:
2055
0
  smbconf_shutdown(ctx);
2056
0
  return werr;
2057
0
}
2058
2059
/****************************************************************
2060
****************************************************************/
2061
2062
static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
2063
0
{
2064
0
  WERROR werr = WERR_OK;
2065
0
  sbcErr err;
2066
0
  struct smbconf_ctx *ctx;
2067
2068
0
  err = smbconf_init_reg(r, &ctx, NULL);
2069
0
  if (!SBC_ERROR_IS_OK(err)) {
2070
0
    werr = WERR_SERVICE_DOES_NOT_EXIST;
2071
0
    goto done;
2072
0
  }
2073
2074
0
  if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2075
2076
0
    err = smbconf_set_global_parameter(ctx, "security", "user");
2077
0
    if (!SBC_ERROR_IS_OK(err)) {
2078
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2079
0
      goto done;
2080
0
    }
2081
2082
0
    err = smbconf_delete_global_parameter(ctx, "workgroup");
2083
0
    if (!SBC_ERROR_IS_OK(err)) {
2084
0
      werr = WERR_SERVICE_DOES_NOT_EXIST;
2085
0
      goto done;
2086
0
    }
2087
2088
0
    smbconf_delete_global_parameter(ctx, "realm");
2089
0
  }
2090
2091
0
 done:
2092
0
  smbconf_shutdown(ctx);
2093
0
  return werr;
2094
0
}
2095
2096
/****************************************************************
2097
****************************************************************/
2098
2099
static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2100
0
{
2101
0
  WERROR werr;
2102
2103
0
  if (!W_ERROR_IS_OK(r->out.result)) {
2104
0
    return r->out.result;
2105
0
  }
2106
2107
0
  if (!r->in.modify_config) {
2108
0
    return WERR_OK;
2109
0
  }
2110
2111
0
  werr = do_join_modify_vals_config(r);
2112
0
  if (!W_ERROR_IS_OK(werr)) {
2113
0
    return werr;
2114
0
  }
2115
2116
0
  lp_load_global(get_dyn_CONFIGFILE());
2117
2118
0
  r->out.modified_config = true;
2119
0
  r->out.result = werr;
2120
2121
0
  return werr;
2122
0
}
2123
2124
/****************************************************************
2125
****************************************************************/
2126
2127
static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2128
0
{
2129
0
  WERROR werr;
2130
2131
0
  if (!W_ERROR_IS_OK(r->out.result)) {
2132
0
    return r->out.result;
2133
0
  }
2134
2135
0
  if (!r->in.modify_config) {
2136
0
    return WERR_OK;
2137
0
  }
2138
2139
0
  werr = do_unjoin_modify_vals_config(r);
2140
0
  if (!W_ERROR_IS_OK(werr)) {
2141
0
    return werr;
2142
0
  }
2143
2144
0
  lp_load_global(get_dyn_CONFIGFILE());
2145
2146
0
  r->out.modified_config = true;
2147
0
  r->out.result = werr;
2148
2149
0
  return werr;
2150
0
}
2151
2152
/****************************************************************
2153
****************************************************************/
2154
2155
static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2156
           const char *domain_str,
2157
           const char **domain_p,
2158
           const char **dc_p)
2159
0
{
2160
0
  char *domain = NULL;
2161
0
  char *dc = NULL;
2162
0
  const char *p = NULL;
2163
2164
0
  if (!domain_str || !domain_p || !dc_p) {
2165
0
    return false;
2166
0
  }
2167
2168
0
  p = strchr_m(domain_str, '\\');
2169
2170
0
  if (p != NULL) {
2171
0
    domain = talloc_strndup(mem_ctx, domain_str,
2172
0
           PTR_DIFF(p, domain_str));
2173
0
    dc = talloc_strdup(mem_ctx, p+1);
2174
0
    if (!dc) {
2175
0
      return false;
2176
0
    }
2177
0
  } else {
2178
0
    domain = talloc_strdup(mem_ctx, domain_str);
2179
0
    dc = NULL;
2180
0
  }
2181
0
  if (!domain) {
2182
0
    return false;
2183
0
  }
2184
2185
0
  *domain_p = domain;
2186
2187
0
  if (!*dc_p && dc) {
2188
0
    *dc_p = dc;
2189
0
  }
2190
2191
0
  return true;
2192
0
}
2193
2194
/****************************************************************
2195
****************************************************************/
2196
2197
static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2198
           struct libnet_JoinCtx *r)
2199
0
{
2200
0
  if (!r->in.domain_name) {
2201
0
    libnet_join_set_error_string(mem_ctx, r,
2202
0
      "No domain name defined");
2203
0
    return WERR_INVALID_PARAMETER;
2204
0
  }
2205
2206
0
  if (strlen(r->in.machine_name) > 15) {
2207
0
    libnet_join_set_error_string(mem_ctx, r,
2208
0
      "Our netbios name can be at most 15 chars long, "
2209
0
                         "\"%s\" is %u chars long\n",
2210
0
                         r->in.machine_name,
2211
0
       (unsigned int)strlen(r->in.machine_name));
2212
0
    return WERR_INVALID_PARAMETER;
2213
0
        }
2214
2215
0
  r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2216
0
               r->in.machine_name);
2217
0
  if (r->out.account_name == NULL) {
2218
0
    libnet_join_set_error_string(mem_ctx, r,
2219
0
      "Unable to construct r->out.account_name");
2220
0
    return WERR_NOT_ENOUGH_MEMORY;
2221
0
  }
2222
2223
0
  if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2224
0
            &r->in.domain_name,
2225
0
            &r->in.dc_name)) {
2226
0
    libnet_join_set_error_string(mem_ctx, r,
2227
0
      "Failed to parse domain name");
2228
0
    return WERR_INVALID_PARAMETER;
2229
0
  }
2230
2231
0
  if (r->in.request_offline_join) {
2232
    /*
2233
     * When in the "request offline join" path we do not have admin
2234
     * credentials available so we can skip the next steps - gd
2235
     */
2236
0
    return WERR_OK;
2237
0
  }
2238
2239
0
  if (r->in.provision_computer_account_only) {
2240
    /*
2241
     * When in the "provision_computer_account_only" path we do not
2242
     * need to have access to secrets.tdb at all - gd
2243
     */
2244
0
    return WERR_OK;
2245
0
  }
2246
2247
0
  if (!secrets_init()) {
2248
0
    libnet_join_set_error_string(mem_ctx, r,
2249
0
      "Unable to open secrets database");
2250
0
    return WERR_CAN_NOT_COMPLETE;
2251
0
  }
2252
2253
0
  return WERR_OK;
2254
0
}
2255
2256
/****************************************************************
2257
****************************************************************/
2258
2259
static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2260
0
{
2261
0
  NTSTATUS status;
2262
2263
  /* Try adding dom admins to builtin\admins. Only log failures. */
2264
0
  status = create_builtin_administrators(domain_sid);
2265
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2266
0
    DEBUG(10,("Unable to auto-add domain administrators to "
2267
0
        "BUILTIN\\Administrators during join because "
2268
0
        "winbindd must be running.\n"));
2269
0
  } else if (!NT_STATUS_IS_OK(status)) {
2270
0
    DEBUG(5, ("Failed to auto-add domain administrators to "
2271
0
        "BUILTIN\\Administrators during join: %s\n",
2272
0
        nt_errstr(status)));
2273
0
  }
2274
2275
  /* Try adding dom users to builtin\users. Only log failures. */
2276
0
  status = create_builtin_users(domain_sid);
2277
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2278
0
    DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2279
0
        "during join because winbindd must be running.\n"));
2280
0
  } else if (!NT_STATUS_IS_OK(status)) {
2281
0
    DEBUG(5, ("Failed to auto-add domain administrators to "
2282
0
        "BUILTIN\\Administrators during join: %s\n",
2283
0
        nt_errstr(status)));
2284
0
  }
2285
2286
  /* Try adding dom guests to builtin\guests. Only log failures. */
2287
0
  status = create_builtin_guests(domain_sid);
2288
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2289
0
    DEBUG(10,("Unable to auto-add domain guests to "
2290
0
        "BUILTIN\\Guests during join because "
2291
0
        "winbindd must be running.\n"));
2292
0
  } else if (!NT_STATUS_IS_OK(status)) {
2293
0
    DEBUG(5, ("Failed to auto-add domain guests to "
2294
0
        "BUILTIN\\Guests during join: %s\n",
2295
0
        nt_errstr(status)));
2296
0
  }
2297
0
}
2298
2299
/****************************************************************
2300
****************************************************************/
2301
2302
static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2303
            struct libnet_JoinCtx *r)
2304
0
{
2305
0
  WERROR werr;
2306
2307
0
  if (!W_ERROR_IS_OK(r->out.result)) {
2308
0
    return r->out.result;
2309
0
  }
2310
2311
0
  if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2312
0
    werr = do_JoinConfig(r);
2313
0
    if (!W_ERROR_IS_OK(werr)) {
2314
0
      return werr;
2315
0
    }
2316
2317
0
    return WERR_OK;
2318
0
  }
2319
2320
0
#ifdef HAVE_ADS
2321
0
  if (r->out.domain_is_ad &&
2322
0
      !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2323
0
    ADS_STATUS ads_status;
2324
2325
0
    ads_status  = libnet_join_post_processing_ads_modify(mem_ctx, r);
2326
0
    if (!ADS_ERR_OK(ads_status)) {
2327
0
      return WERR_GEN_FAILURE;
2328
0
    }
2329
0
  }
2330
0
#endif /* HAVE_ADS */
2331
2332
0
  if (r->in.provision_computer_account_only) {
2333
    /*
2334
     * When we only provision a computer account we are done here - gd.
2335
     */
2336
0
    return WERR_OK;
2337
0
  }
2338
2339
0
  saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2340
0
  if (r->out.dns_domain_name) {
2341
0
    saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2342
0
  }
2343
2344
0
  if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2345
0
    return WERR_NERR_SETUPNOTJOINED;
2346
0
  }
2347
2348
0
  werr = do_JoinConfig(r);
2349
0
  if (!W_ERROR_IS_OK(werr)) {
2350
0
    return werr;
2351
0
  }
2352
2353
0
#ifdef HAVE_ADS
2354
0
  if (r->out.domain_is_ad &&
2355
0
      !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2356
0
    ADS_STATUS ads_status;
2357
2358
0
    ads_status  = libnet_join_post_processing_ads_sync(mem_ctx, r);
2359
0
    if (!ADS_ERR_OK(ads_status)) {
2360
0
      return WERR_GEN_FAILURE;
2361
0
    }
2362
0
  }
2363
0
#endif /* HAVE_ADS */
2364
2365
0
  libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2366
2367
0
  return WERR_OK;
2368
0
}
2369
2370
/****************************************************************
2371
****************************************************************/
2372
2373
static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2374
0
{
2375
0
  TALLOC_FREE(r->in.ads);
2376
2377
0
  return 0;
2378
0
}
2379
2380
/****************************************************************
2381
****************************************************************/
2382
2383
static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2384
0
{
2385
0
  TALLOC_FREE(r->in.ads);
2386
2387
0
  return 0;
2388
0
}
2389
2390
/****************************************************************
2391
****************************************************************/
2392
2393
WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2394
         struct libnet_JoinCtx **r)
2395
0
{
2396
0
  struct libnet_JoinCtx *ctx;
2397
2398
0
  ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2399
0
  if (!ctx) {
2400
0
    return WERR_NOT_ENOUGH_MEMORY;
2401
0
  }
2402
2403
0
  talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2404
2405
0
  ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2406
0
  W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2407
2408
0
  ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2409
2410
0
  ctx->in.desired_encryption_types = 0;
2411
0
  ctx->in.desired_encryption_types |= ENC_RC4_HMAC_MD5;
2412
0
  ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2413
0
  ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2414
2415
0
  *r = ctx;
2416
2417
0
  return WERR_OK;
2418
0
}
2419
2420
/****************************************************************
2421
****************************************************************/
2422
2423
WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2424
           struct libnet_UnjoinCtx **r)
2425
0
{
2426
0
  struct libnet_UnjoinCtx *ctx;
2427
2428
0
  ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2429
0
  if (!ctx) {
2430
0
    return WERR_NOT_ENOUGH_MEMORY;
2431
0
  }
2432
2433
0
  talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2434
2435
0
  ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2436
0
  W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2437
2438
0
  *r = ctx;
2439
2440
0
  return WERR_OK;
2441
0
}
2442
2443
/****************************************************************
2444
****************************************************************/
2445
2446
static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2447
               struct libnet_JoinCtx *r)
2448
0
{
2449
0
  bool valid_security = false;
2450
0
  bool valid_workgroup = false;
2451
0
  bool valid_realm = false;
2452
0
  bool valid_hostname = false;
2453
0
  bool ignored_realm = false;
2454
2455
  /* check if configuration is already set correctly */
2456
2457
0
  valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2458
0
  valid_hostname = strequal(lp_netbios_name(), r->in.machine_name);
2459
2460
0
  switch (r->out.domain_is_ad) {
2461
0
    case false:
2462
0
      valid_security = (lp_security() == SEC_DOMAIN)
2463
0
        || (lp_server_role() == ROLE_DOMAIN_PDC)
2464
0
        || (lp_server_role() == ROLE_DOMAIN_BDC);
2465
0
      if (valid_workgroup && valid_security) {
2466
        /* nothing to be done */
2467
0
        return WERR_OK;
2468
0
      }
2469
0
      break;
2470
0
    case true:
2471
0
      valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2472
0
      switch (lp_security()) {
2473
0
      case SEC_DOMAIN:
2474
0
        if (!valid_realm && lp_winbind_rpc_only()) {
2475
0
          valid_realm = true;
2476
0
          ignored_realm = true;
2477
0
        }
2478
2479
0
        FALL_THROUGH;
2480
0
      case SEC_ADS:
2481
0
        valid_security = true;
2482
0
      }
2483
2484
0
      if (valid_workgroup && valid_realm && valid_security &&
2485
0
          valid_hostname) {
2486
0
        if (ignored_realm && !r->in.modify_config)
2487
0
        {
2488
0
          libnet_join_set_error_string(mem_ctx, r,
2489
0
            "Warning: ignoring realm when "
2490
0
            "joining AD domain with "
2491
0
            "'security=domain' and "
2492
0
            "'winbind rpc only = yes'. "
2493
0
            "(realm set to '%s', "
2494
0
            "should be '%s').", lp_realm(),
2495
0
            r->out.dns_domain_name);
2496
0
        }
2497
        /* nothing to be done */
2498
0
        return WERR_OK;
2499
0
      }
2500
0
      break;
2501
0
  }
2502
2503
  /* check if we are supposed to manipulate configuration */
2504
2505
0
  if (!r->in.modify_config) {
2506
2507
0
    char *wrong_conf = talloc_strdup(mem_ctx, "");
2508
2509
0
    if (!valid_hostname) {
2510
0
      wrong_conf = talloc_asprintf_append(wrong_conf,
2511
0
        "\"netbios name\" set to '%s', should be '%s'",
2512
0
        lp_netbios_name(), r->in.machine_name);
2513
0
      W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2514
0
    }
2515
2516
0
    if (!valid_workgroup) {
2517
0
      wrong_conf = talloc_asprintf_append(wrong_conf,
2518
0
        "\"workgroup\" set to '%s', should be '%s'",
2519
0
        lp_workgroup(), r->out.netbios_domain_name);
2520
0
      W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2521
0
    }
2522
2523
0
    if (!valid_realm) {
2524
0
      wrong_conf = talloc_asprintf_append(wrong_conf,
2525
0
        "\"realm\" set to '%s', should be '%s'",
2526
0
        lp_realm(), r->out.dns_domain_name);
2527
0
      W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2528
0
    }
2529
2530
0
    if (!valid_security) {
2531
0
      const char *sec = NULL;
2532
0
      switch (lp_security()) {
2533
0
      case SEC_USER:  sec = "user"; break;
2534
0
      case SEC_DOMAIN: sec = "domain"; break;
2535
0
      case SEC_ADS: sec = "ads"; break;
2536
0
      }
2537
0
      wrong_conf = talloc_asprintf_append(wrong_conf,
2538
0
        "\"security\" set to '%s', should be %s",
2539
0
        sec, r->out.domain_is_ad ?
2540
0
        "either 'domain' or 'ads'" : "'domain'");
2541
0
      W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2542
0
    }
2543
2544
0
    libnet_join_set_error_string(mem_ctx, r,
2545
0
      "Invalid configuration (%s) and configuration modification "
2546
0
      "was not requested", wrong_conf);
2547
0
    return WERR_CAN_NOT_COMPLETE;
2548
0
  }
2549
2550
  /* check if we are able to manipulate configuration */
2551
2552
0
  if (!lp_config_backend_is_registry()) {
2553
0
    libnet_join_set_error_string(mem_ctx, r,
2554
0
      "Configuration manipulation requested but not "
2555
0
      "supported by backend");
2556
0
    return WERR_NOT_SUPPORTED;
2557
0
  }
2558
2559
0
  return WERR_OK;
2560
0
}
2561
2562
/****************************************************************
2563
****************************************************************/
2564
2565
static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2566
        struct libnet_JoinCtx *r)
2567
0
{
2568
0
  NTSTATUS status;
2569
0
  WERROR werr;
2570
0
  struct cli_state *cli = NULL;
2571
0
#ifdef HAVE_ADS
2572
0
  ADS_STATUS ads_status;
2573
0
#endif /* HAVE_ADS */
2574
0
  const char *pre_connect_realm = NULL;
2575
0
  const char *sitename = NULL;
2576
0
  struct netr_DsRGetDCNameInfo *info;
2577
0
  const char *dc;
2578
0
  uint32_t name_type_flags = 0;
2579
2580
  /* Before contacting a DC, we can securely know
2581
   * the realm only if the user specifies it.
2582
   */
2583
0
  if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2584
0
    pre_connect_realm = r->in.domain_name;
2585
0
  }
2586
2587
0
  if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2588
0
    name_type_flags = DS_IS_DNS_NAME;
2589
0
  } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2590
0
    name_type_flags = DS_IS_FLAT_NAME;
2591
0
  }
2592
2593
0
  if (r->in.dc_name) {
2594
0
    status = dsgetonedcname(mem_ctx,
2595
0
          r->in.msg_ctx,
2596
0
          r->in.domain_name,
2597
0
          r->in.dc_name,
2598
0
          DS_DIRECTORY_SERVICE_REQUIRED |
2599
0
          DS_WRITABLE_REQUIRED |
2600
0
          DS_RETURN_DNS_NAME |
2601
0
          name_type_flags,
2602
0
          &info);
2603
0
  } else {
2604
0
    status = dsgetdcname(mem_ctx,
2605
0
             r->in.msg_ctx,
2606
0
             r->in.domain_name,
2607
0
             NULL,
2608
0
             NULL,
2609
0
             DS_FORCE_REDISCOVERY |
2610
0
             DS_DIRECTORY_SERVICE_REQUIRED |
2611
0
             DS_WRITABLE_REQUIRED |
2612
0
             DS_RETURN_DNS_NAME |
2613
0
             name_type_flags,
2614
0
             &info);
2615
0
  }
2616
0
  if (!NT_STATUS_IS_OK(status)) {
2617
0
    libnet_join_set_error_string(mem_ctx, r,
2618
0
      "failed to find DC for domain %s - %s",
2619
0
      r->in.domain_name,
2620
0
      get_friendly_nt_error_msg(status));
2621
0
    return WERR_NERR_DCNOTFOUND;
2622
0
  }
2623
2624
0
  dc = strip_hostname(info->dc_unc);
2625
0
  r->in.dc_name = talloc_strdup(mem_ctx, dc);
2626
0
  W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2627
2628
0
  if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2629
0
      info->dc_address[1] != '\\') {
2630
0
    DBG_ERR("ill-formed DC address '%s'\n",
2631
0
      info->dc_address);
2632
0
    return WERR_NERR_DCNOTFOUND;
2633
0
  }
2634
2635
0
  sitename = info->dc_site_name;
2636
  /* info goes out of scope but the memory stays
2637
     allocated on the talloc context */
2638
2639
  /* return the allocated netr_DsRGetDCNameInfo struct */
2640
0
  r->out.dcinfo = info;
2641
2642
0
  if (pre_connect_realm != NULL) {
2643
0
    struct sockaddr_storage ss = {0};
2644
0
    const char *numeric_dcip = info->dc_address + 2;
2645
2646
0
    if (numeric_dcip[0] == '\0') {
2647
0
      if (!interpret_string_addr(&ss, numeric_dcip,
2648
0
               AI_NUMERICHOST)) {
2649
0
        DBG_ERR(
2650
0
            "cannot parse IP address '%s' of DC '%s'\n",
2651
0
            numeric_dcip, r->in.dc_name);
2652
0
        return WERR_NERR_DCNOTFOUND;
2653
0
      }
2654
0
    } else {
2655
0
      if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2656
0
        DBG_WARNING(
2657
0
            "cannot resolve IP address of DC '%s'\n",
2658
0
            r->in.dc_name);
2659
0
        return WERR_NERR_DCNOTFOUND;
2660
0
      }
2661
0
    }
2662
2663
    /* The domain parameter is only used as modifier
2664
     * to krb5.conf file name. _JOIN_ is not a valid
2665
     * NetBIOS name so it cannot clash with another domain
2666
     * -- Uri.
2667
     */
2668
0
    create_local_private_krb5_conf_for_domain(pre_connect_realm,
2669
0
                "_JOIN_",
2670
0
                sitename,
2671
0
                &ss);
2672
0
  }
2673
2674
0
  status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2675
0
  if (!NT_STATUS_IS_OK(status)) {
2676
0
    libnet_join_set_error_string(mem_ctx, r,
2677
0
      "failed to lookup DC info for domain '%s' over rpc: %s",
2678
0
      r->in.domain_name, get_friendly_nt_error_msg(status));
2679
0
    return ntstatus_to_werror(status);
2680
0
  }
2681
2682
0
  werr = libnet_join_check_config(mem_ctx, r);
2683
0
  if (!W_ERROR_IS_OK(werr)) {
2684
0
    if (!r->in.provision_computer_account_only) {
2685
0
      goto done;
2686
0
    }
2687
    /* do not fail when only provisioning */
2688
0
  }
2689
2690
0
#ifdef HAVE_ADS
2691
2692
0
  if (r->out.domain_is_ad) {
2693
0
    create_local_private_krb5_conf_for_domain(
2694
0
      r->out.dns_domain_name, r->out.netbios_domain_name,
2695
0
      sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2696
0
  }
2697
2698
0
  if (r->out.domain_is_ad &&
2699
0
      !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2700
2701
0
    const char *initial_account_ou = r->in.account_ou;
2702
2703
    /*
2704
     * we want to create the msDS-SupportedEncryptionTypes attribute
2705
     * as early as possible so always try an LDAP create as the user
2706
     * first. We copy r->in.account_ou because it may be changed
2707
     * during the machine pre-creation.
2708
     */
2709
2710
0
    ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2711
0
    if (!ADS_ERR_OK(ads_status)) {
2712
0
      libnet_join_set_error_string(mem_ctx, r,
2713
0
        "failed to connect to AD: %s",
2714
0
        ads_errstr(ads_status));
2715
0
      return WERR_NERR_DEFAULTJOINREQUIRED;
2716
0
    }
2717
2718
0
    ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2719
0
    if (ADS_ERR_OK(ads_status)) {
2720
2721
      /*
2722
       * LDAP object creation succeeded.
2723
       */
2724
0
      r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2725
2726
0
      return WERR_OK;
2727
0
    }
2728
2729
0
    if (initial_account_ou != NULL) {
2730
0
      libnet_join_set_error_string(mem_ctx, r,
2731
0
        "failed to precreate account in ou %s: %s",
2732
0
        r->in.account_ou,
2733
0
        ads_errstr(ads_status));
2734
0
      return WERR_NERR_DEFAULTJOINREQUIRED;
2735
0
    }
2736
2737
0
    DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2738
0
       r->in.account_ou, ads_errstr(ads_status));
2739
0
  }
2740
0
#endif /* HAVE_ADS */
2741
2742
0
  if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2743
0
      (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2744
0
    status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2745
0
  } else {
2746
0
    status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2747
0
  }
2748
0
  if (!NT_STATUS_IS_OK(status)) {
2749
0
    libnet_join_set_error_string(mem_ctx, r,
2750
0
      "failed to join domain '%s' over rpc: %s",
2751
0
      r->in.domain_name, get_friendly_nt_error_msg(status));
2752
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2753
0
      return WERR_NERR_SETUPALREADYJOINED;
2754
0
    }
2755
0
    werr = ntstatus_to_werror(status);
2756
0
    goto done;
2757
0
  }
2758
2759
0
  werr = WERR_OK;
2760
2761
0
 done:
2762
0
  if (cli) {
2763
0
    cli_shutdown(cli);
2764
0
  }
2765
2766
0
  return werr;
2767
0
}
2768
2769
/****************************************************************
2770
****************************************************************/
2771
2772
static WERROR libnet_DomainOfflineJoin(TALLOC_CTX *mem_ctx,
2773
               struct libnet_JoinCtx *r)
2774
0
{
2775
0
  NTSTATUS status;
2776
0
  WERROR werr;
2777
0
  struct ODJ_WIN7BLOB win7blob;
2778
0
  struct OP_JOINPROV3_PART joinprov3;
2779
0
  const char *dc_name;
2780
2781
0
  if (!r->in.request_offline_join) {
2782
0
    return WERR_NERR_DEFAULTJOINREQUIRED;
2783
0
  }
2784
2785
0
  if (r->in.odj_provision_data == NULL) {
2786
0
    return WERR_INVALID_PARAMETER;
2787
0
  }
2788
2789
0
  werr = libnet_odj_find_win7blob(r->in.odj_provision_data, &win7blob);
2790
0
  if (!W_ERROR_IS_OK(werr)) {
2791
0
    return werr;
2792
0
  }
2793
2794
0
  r->out.netbios_domain_name = talloc_strdup(mem_ctx,
2795
0
      win7blob.DnsDomainInfo.Name.string);
2796
0
  W_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
2797
2798
0
  r->out.dns_domain_name = talloc_strdup(mem_ctx,
2799
0
      win7blob.DnsDomainInfo.DnsDomainName.string);
2800
0
  W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2801
2802
0
  r->out.forest_name = talloc_strdup(mem_ctx,
2803
0
      win7blob.DnsDomainInfo.DnsForestName.string);
2804
0
  W_ERROR_HAVE_NO_MEMORY(r->out.forest_name);
2805
2806
0
  r->out.domain_guid = win7blob.DnsDomainInfo.DomainGuid;
2807
0
  r->out.domain_sid = dom_sid_dup(mem_ctx,
2808
0
      win7blob.DnsDomainInfo.Sid);
2809
0
  W_ERROR_HAVE_NO_MEMORY(r->out.domain_sid);
2810
2811
0
  werr = libnet_odj_find_joinprov3(r->in.odj_provision_data, &joinprov3);
2812
0
  if (!W_ERROR_IS_OK(werr)) {
2813
0
    return werr;
2814
0
  }
2815
2816
0
  r->out.account_rid = joinprov3.Rid;
2817
2818
0
  dc_name = strip_hostname(win7blob.DcInfo.dc_address);
2819
0
  if (dc_name == NULL) {
2820
0
    return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
2821
0
  }
2822
0
  r->in.dc_name = talloc_strdup(mem_ctx, dc_name);
2823
0
  W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2824
2825
0
  r->out.domain_is_ad = true;
2826
2827
  /* we cannot use talloc_steal but have to deep copy the struct here */
2828
0
  status = copy_netr_DsRGetDCNameInfo(mem_ctx, &win7blob.DcInfo,
2829
0
              &r->out.dcinfo);
2830
0
  if (!NT_STATUS_IS_OK(status)) {
2831
0
    return ntstatus_to_werror(status);
2832
0
  }
2833
2834
0
  werr = libnet_join_check_config(mem_ctx, r);
2835
0
  if (!W_ERROR_IS_OK(werr)) {
2836
0
    return werr;
2837
0
  }
2838
2839
0
  return WERR_OK;
2840
#if 0
2841
  /* the following fields are currently not filled in */
2842
2843
  const char * dn;
2844
  uint32_t set_encryption_types;
2845
  const char * krb5_salt;
2846
#endif
2847
0
}
2848
2849
/****************************************************************
2850
****************************************************************/
2851
2852
static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2853
           struct libnet_JoinCtx *r)
2854
0
{
2855
0
  WERROR werr;
2856
0
  struct libnet_UnjoinCtx *u = NULL;
2857
2858
0
  werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2859
0
  if (!W_ERROR_IS_OK(werr)) {
2860
0
    return werr;
2861
0
  }
2862
2863
0
  u->in.debug   = r->in.debug;
2864
0
  u->in.dc_name   = r->in.dc_name;
2865
0
  u->in.domain_name = r->in.domain_name;
2866
0
  u->in.admin_credentials = r->in.admin_credentials;
2867
0
  u->in.modify_config = r->in.modify_config;
2868
0
  u->in.unjoin_flags  = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2869
0
          WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2870
2871
0
  werr = libnet_Unjoin(mem_ctx, u);
2872
0
  TALLOC_FREE(u);
2873
2874
0
  return werr;
2875
0
}
2876
2877
/****************************************************************
2878
****************************************************************/
2879
2880
WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2881
       struct libnet_JoinCtx *r)
2882
0
{
2883
0
  WERROR werr;
2884
2885
0
  if (r->in.debug) {
2886
0
    LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2887
0
  }
2888
2889
0
  ZERO_STRUCT(r->out);
2890
2891
0
  werr = libnet_join_pre_processing(mem_ctx, r);
2892
0
  if (!W_ERROR_IS_OK(werr)) {
2893
0
    goto done;
2894
0
  }
2895
2896
0
  if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2897
0
    if (r->in.request_offline_join) {
2898
0
      werr = libnet_DomainOfflineJoin(mem_ctx, r);
2899
0
    } else {
2900
0
      werr = libnet_DomainJoin(mem_ctx, r);
2901
0
    }
2902
0
    if (!W_ERROR_IS_OK(werr)) {
2903
0
      goto done;
2904
0
    }
2905
0
  }
2906
2907
0
  werr = libnet_join_post_processing(mem_ctx, r);
2908
0
  if (!W_ERROR_IS_OK(werr)) {
2909
0
    goto done;
2910
0
  }
2911
2912
0
  if (r->in.provision_computer_account_only) {
2913
    /*
2914
     * When we only provision a computer account we are done here - gd.
2915
     */
2916
0
    goto done;
2917
0
  }
2918
2919
0
  if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2920
0
    if (r->in.request_offline_join) {
2921
      /*
2922
       * When we are serving an offline domain join request we
2923
       * have no network so we are done here - gd.
2924
       */
2925
0
      goto done;
2926
0
    }
2927
2928
0
    werr = libnet_join_post_verify(mem_ctx, r);
2929
0
    if (!W_ERROR_IS_OK(werr)) {
2930
0
      libnet_join_rollback(mem_ctx, r);
2931
0
    }
2932
0
  }
2933
2934
0
 done:
2935
0
  r->out.result = werr;
2936
2937
0
  if (r->in.debug) {
2938
0
    LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2939
0
  }
2940
0
  return werr;
2941
0
}
2942
2943
/****************************************************************
2944
****************************************************************/
2945
2946
static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2947
          struct libnet_UnjoinCtx *r)
2948
0
{
2949
0
  NTSTATUS status;
2950
2951
0
  if (!r->in.domain_sid) {
2952
0
    struct dom_sid sid;
2953
0
    if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2954
0
      libnet_unjoin_set_error_string(mem_ctx, r,
2955
0
        "Unable to fetch domain sid: are we joined?");
2956
0
      return WERR_NERR_SETUPNOTJOINED;
2957
0
    }
2958
0
    r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2959
0
    W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2960
0
  }
2961
2962
0
  if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2963
0
      !r->in.delete_machine_account) {
2964
0
    libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2965
0
    return WERR_OK;
2966
0
  }
2967
2968
0
  if (!r->in.dc_name) {
2969
0
    struct netr_DsRGetDCNameInfo *info;
2970
0
    const char *dc;
2971
0
    status = dsgetdcname(mem_ctx,
2972
0
             r->in.msg_ctx,
2973
0
             r->in.domain_name,
2974
0
             NULL,
2975
0
             NULL,
2976
0
             DS_DIRECTORY_SERVICE_REQUIRED |
2977
0
             DS_WRITABLE_REQUIRED |
2978
0
             DS_RETURN_DNS_NAME,
2979
0
             &info);
2980
0
    if (!NT_STATUS_IS_OK(status)) {
2981
0
      libnet_unjoin_set_error_string(mem_ctx, r,
2982
0
        "failed to find DC for domain %s - %s",
2983
0
        r->in.domain_name,
2984
0
        get_friendly_nt_error_msg(status));
2985
0
      return WERR_NERR_DCNOTFOUND;
2986
0
    }
2987
2988
0
    dc = strip_hostname(info->dc_unc);
2989
0
    r->in.dc_name = talloc_strdup(mem_ctx, dc);
2990
0
    W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2991
0
  }
2992
2993
0
#ifdef HAVE_ADS
2994
  /* for net ads leave, try to delete the account.  If it works,
2995
     no sense in disabling.  If it fails, we can still try to
2996
     disable it. jmcd */
2997
2998
0
  if (r->in.delete_machine_account) {
2999
0
    ADS_STATUS ads_status;
3000
0
    ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
3001
0
    if (ADS_ERR_OK(ads_status)) {
3002
      /* dirty hack */
3003
0
      r->out.dns_domain_name =
3004
0
        talloc_strdup(mem_ctx,
3005
0
                r->in.ads->server.realm);
3006
0
      ads_status =
3007
0
        libnet_unjoin_remove_machine_acct(mem_ctx, r);
3008
0
    }
3009
0
    if (!ADS_ERR_OK(ads_status)) {
3010
0
      libnet_unjoin_set_error_string(mem_ctx, r,
3011
0
        "failed to remove machine account from AD: %s",
3012
0
        ads_errstr(ads_status));
3013
0
    } else {
3014
0
      r->out.deleted_machine_account = true;
3015
0
      W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
3016
0
      libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3017
0
      return WERR_OK;
3018
0
    }
3019
0
  }
3020
0
#endif /* HAVE_ADS */
3021
3022
  /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
3023
     "disable".  */
3024
0
  if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
3025
0
    status = libnet_join_unjoindomain_rpc(mem_ctx, r);
3026
0
    if (!NT_STATUS_IS_OK(status)) {
3027
0
      libnet_unjoin_set_error_string(mem_ctx, r,
3028
0
        "failed to disable machine account via rpc: %s",
3029
0
        get_friendly_nt_error_msg(status));
3030
0
      if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
3031
0
        return WERR_NERR_SETUPNOTJOINED;
3032
0
      }
3033
0
      return ntstatus_to_werror(status);
3034
0
    }
3035
3036
0
    r->out.dns_domain_name = talloc_strdup(mem_ctx,
3037
0
                              r->in.domain_name);
3038
0
    r->out.disabled_machine_account = true;
3039
0
  }
3040
3041
  /* If disable succeeded or was not requested at all, we
3042
     should be getting rid of our end of things */
3043
3044
0
  libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3045
3046
0
  return WERR_OK;
3047
0
}
3048
3049
/****************************************************************
3050
****************************************************************/
3051
3052
static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
3053
             struct libnet_UnjoinCtx *r)
3054
0
{
3055
0
  if (!r->in.domain_name) {
3056
0
    libnet_unjoin_set_error_string(mem_ctx, r,
3057
0
      "No domain name defined");
3058
0
    return WERR_INVALID_PARAMETER;
3059
0
  }
3060
3061
0
  if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
3062
0
            &r->in.domain_name,
3063
0
            &r->in.dc_name)) {
3064
0
    libnet_unjoin_set_error_string(mem_ctx, r,
3065
0
      "Failed to parse domain name");
3066
0
    return WERR_INVALID_PARAMETER;
3067
0
  }
3068
3069
0
  if (IS_DC) {
3070
0
    return WERR_NERR_SETUPDOMAINCONTROLLER;
3071
0
  }
3072
3073
0
  if (!secrets_init()) {
3074
0
    libnet_unjoin_set_error_string(mem_ctx, r,
3075
0
      "Unable to open secrets database");
3076
0
    return WERR_CAN_NOT_COMPLETE;
3077
0
  }
3078
3079
0
  return WERR_OK;
3080
0
}
3081
3082
/****************************************************************
3083
****************************************************************/
3084
3085
static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
3086
              struct libnet_UnjoinCtx *r)
3087
0
{
3088
0
  saf_delete(r->out.netbios_domain_name);
3089
0
  saf_delete(r->out.dns_domain_name);
3090
3091
0
  return libnet_unjoin_config(r);
3092
0
}
3093
3094
/****************************************************************
3095
****************************************************************/
3096
3097
WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
3098
         struct libnet_UnjoinCtx *r)
3099
0
{
3100
0
  WERROR werr;
3101
3102
0
  if (r->in.debug) {
3103
0
    LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
3104
0
  }
3105
3106
0
  werr = libnet_unjoin_pre_processing(mem_ctx, r);
3107
0
  if (!W_ERROR_IS_OK(werr)) {
3108
0
    goto done;
3109
0
  }
3110
3111
0
  if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3112
0
    werr = libnet_DomainUnjoin(mem_ctx, r);
3113
0
    if (!W_ERROR_IS_OK(werr)) {
3114
0
      libnet_unjoin_config(r);
3115
0
      goto done;
3116
0
    }
3117
0
  }
3118
3119
0
  werr = libnet_unjoin_post_processing(mem_ctx, r);
3120
0
  if (!W_ERROR_IS_OK(werr)) {
3121
0
    goto done;
3122
0
  }
3123
3124
0
 done:
3125
0
  r->out.result = werr;
3126
3127
0
  if (r->in.debug) {
3128
0
    LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
3129
0
  }
3130
3131
0
  return werr;
3132
0
}