s3:net: Refactor net_ads_join(), allocate a talloc context
[samba.git] / source3 / utils / net_ads.c
1 /*
2    Samba Unix/Linux SMB client library
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "libsmb/namequery.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "nsswitch/libwbclient/wbclient.h"
30 #include "ads.h"
31 #include "libads/cldap.h"
32 #include "../lib/addns/dnsquery.h"
33 #include "../libds/common/flags.h"
34 #include "librpc/gen_ndr/libnet_join.h"
35 #include "libnet/libnet_join.h"
36 #include "smb_krb5.h"
37 #include "secrets.h"
38 #include "krb5_env.h"
39 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "lib/param/loadparm.h"
42 #include "utils/net_dns.h"
43 #include "auth/kerberos/pac_utils.h"
44 #include "lib/util/string_wrappers.h"
45
46 #ifdef HAVE_JANSSON
47 #include <jansson.h>
48 #include "audit_logging.h" /* various JSON helpers */
49 #include "auth/common_auth.h"
50 #endif /* [HAVE_JANSSON] */
51
52 #ifdef HAVE_ADS
53
54 /* when we do not have sufficient input parameters to contact a remote domain
55  * we always fall back to our own realm - Guenther*/
56
57 static const char *assume_own_realm(struct net_context *c)
58 {
59         if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
60                 return lp_realm();
61         }
62
63         return NULL;
64 }
65
66 #ifdef HAVE_JANSSON
67
68 /*
69  * note: JSON output deliberately bypasses gettext so as to provide the same
70  * output irrespective of the locale.
71  */
72
73 static int output_json(const struct json_object *jsobj)
74 {
75         TALLOC_CTX *ctx = NULL;
76         char *json = NULL;
77
78         if (json_is_invalid(jsobj)) {
79                 return -1;
80         }
81
82         ctx = talloc_new(NULL);
83         if (ctx == NULL) {
84                 d_fprintf(stderr, _("Out of memory\n"));
85                 return -1;
86         }
87
88         json = json_to_string(ctx, jsobj);
89         if (!json) {
90                 d_fprintf(stderr, _("error encoding to JSON\n"));
91                 return -1;
92         }
93
94         d_printf("%s\n", json);
95         TALLOC_FREE(ctx);
96
97         return 0;
98 }
99
100 static int net_ads_cldap_netlogon_json
101         (ADS_STRUCT *ads,
102          const char *addr,
103          const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
104 {
105         struct json_object jsobj = json_new_object();
106         struct json_object flagsobj = json_new_object();
107         char response_type [32] = { '\0' };
108         int ret = 0;
109
110         if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111                 d_fprintf(stderr, _("error setting up JSON value\n"));
112
113                 goto failure;
114         }
115
116         switch (reply->command) {
117                 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
118                         strncpy(response_type,
119                                 "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
120                                 sizeof(response_type));
121                         break;
122                 case LOGON_SAM_LOGON_RESPONSE_EX:
123                         strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
124               sizeof(response_type));
125                         break;
126                 default:
127                         snprintf(response_type, sizeof(response_type), "0x%x",
128                reply->command);
129                         break;
130         }
131
132         ret = json_add_string(&jsobj, "Information for Domain Controller",
133                               addr);
134         if (ret != 0) {
135                 goto failure;
136         }
137
138         ret = json_add_string(&jsobj, "Response Type", response_type);
139         if (ret != 0) {
140                 goto failure;
141         }
142
143         ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
144         if (ret != 0) {
145                 goto failure;
146         }
147
148         ret = json_add_bool(&flagsobj, "Is a PDC",
149                             reply->server_type & NBT_SERVER_PDC);
150         if (ret != 0) {
151                 goto failure;
152         }
153
154         ret = json_add_bool(&flagsobj, "Is a GC of the forest",
155                             reply->server_type & NBT_SERVER_GC);
156         if (ret != 0) {
157                 goto failure;
158         }
159
160         ret = json_add_bool(&flagsobj, "Is an LDAP server",
161                             reply->server_type & NBT_SERVER_LDAP);
162         if (ret != 0) {
163                 goto failure;
164         }
165
166         ret = json_add_bool(&flagsobj, "Supports DS",
167                             reply->server_type & NBT_SERVER_DS);
168         if (ret != 0) {
169                 goto failure;
170         }
171
172         ret = json_add_bool(&flagsobj, "Is running a KDC",
173                             reply->server_type & NBT_SERVER_KDC);
174         if (ret != 0) {
175                 goto failure;
176         }
177
178         ret = json_add_bool(&flagsobj, "Is running time services",
179                             reply->server_type & NBT_SERVER_TIMESERV);
180         if (ret != 0) {
181                 goto failure;
182         }
183
184         ret = json_add_bool(&flagsobj, "Is the closest DC",
185                             reply->server_type & NBT_SERVER_CLOSEST);
186         if (ret != 0) {
187                 goto failure;
188         }
189
190         ret = json_add_bool(&flagsobj, "Is writable",
191                             reply->server_type & NBT_SERVER_WRITABLE);
192         if (ret != 0) {
193                 goto failure;
194         }
195
196         ret = json_add_bool(&flagsobj, "Has a hardware clock",
197                             reply->server_type & NBT_SERVER_GOOD_TIMESERV);
198         if (ret != 0) {
199                 goto failure;
200         }
201
202         ret = json_add_bool(&flagsobj,
203                             "Is a non-domain NC serviced by LDAP server",
204                             reply->server_type & NBT_SERVER_NDNC);
205         if (ret != 0) {
206                 goto failure;
207         }
208
209         ret = json_add_bool
210                 (&flagsobj, "Is NT6 DC that has some secrets",
211                  reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
212         if (ret != 0) {
213                 goto failure;
214         }
215
216         ret = json_add_bool
217                 (&flagsobj, "Is NT6 DC that has all secrets",
218                  reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
219         if (ret != 0) {
220                 goto failure;
221         }
222
223         ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
224                             reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
225         if (ret != 0) {
226                 goto failure;
227         }
228
229         ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
230                             reply->server_type & NBT_SERVER_DS_8);
231         if (ret != 0) {
232                 goto failure;
233         }
234
235         ret = json_add_string(&jsobj, "Forest", reply->forest);
236         if (ret != 0) {
237                 goto failure;
238         }
239
240         ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
241         if (ret != 0) {
242                 goto failure;
243         }
244
245         ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
246         if (ret != 0) {
247                 goto failure;
248         }
249
250
251         ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
252         if (ret != 0) {
253                 goto failure;
254         }
255
256         ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
257         if (ret != 0) {
258                 goto failure;
259         }
260
261         if (*reply->user_name) {
262                 ret = json_add_string(&jsobj, "User name", reply->user_name);
263                 if (ret != 0) {
264                         goto failure;
265                 }
266         }
267
268         ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
269         if (ret != 0) {
270                 goto failure;
271         }
272
273         ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
274         if (ret != 0) {
275                 goto failure;
276         }
277
278         ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
279         if (ret != 0) {
280                 goto failure;
281         }
282
283         ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
284         if (ret != 0) {
285                 goto failure;
286         }
287
288         ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
289         if (ret != 0) {
290                 goto failure;
291         }
292
293         ret = json_add_object(&jsobj, "Flags", &flagsobj);
294         if (ret != 0) {
295                 goto failure;
296         }
297
298         ret = output_json(&jsobj);
299         json_free(&jsobj); /* frees flagsobj recursively */
300
301         return ret;
302
303 failure:
304         json_free(&flagsobj);
305         json_free(&jsobj);
306
307         return ret;
308 }
309
310 #else /* [HAVE_JANSSON] */
311
312 static int net_ads_cldap_netlogon_json
313         (ADS_STRUCT *ads,
314          const char *addr,
315          const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
316 {
317         d_fprintf(stderr, _("JSON support not available\n"));
318
319         return -1;
320 }
321
322 #endif /* [HAVE_JANSSON] */
323
324 /*
325   do a cldap netlogon query
326 */
327 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
328 {
329         char addr[INET6_ADDRSTRLEN];
330         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
331
332         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
333
334         if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
335                 d_fprintf(stderr, _("CLDAP query failed!\n"));
336                 return -1;
337         }
338
339         if (c->opt_json) {
340                 return net_ads_cldap_netlogon_json(ads, addr, &reply);
341         }
342
343         d_printf(_("Information for Domain Controller: %s\n\n"),
344                 addr);
345
346         d_printf(_("Response Type: "));
347         switch (reply.command) {
348         case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
349                 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
350                 break;
351         case LOGON_SAM_LOGON_RESPONSE_EX:
352                 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
353                 break;
354         default:
355                 d_printf("0x%x\n", reply.command);
356                 break;
357         }
358
359         d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
360
361         d_printf(_("Flags:\n"
362                    "\tIs a PDC:                                   %s\n"
363                    "\tIs a GC of the forest:                      %s\n"
364                    "\tIs an LDAP server:                          %s\n"
365                    "\tSupports DS:                                %s\n"
366                    "\tIs running a KDC:                           %s\n"
367                    "\tIs running time services:                   %s\n"
368                    "\tIs the closest DC:                          %s\n"
369                    "\tIs writable:                                %s\n"
370                    "\tHas a hardware clock:                       %s\n"
371                    "\tIs a non-domain NC serviced by LDAP server: %s\n"
372                    "\tIs NT6 DC that has some secrets:            %s\n"
373                    "\tIs NT6 DC that has all secrets:             %s\n"
374                    "\tRuns Active Directory Web Services:         %s\n"
375                    "\tRuns on Windows 2012 or later:              %s\n"),
376                    (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
377                    (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
378                    (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
379                    (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
380                    (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
381                    (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
382                    (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
383                    (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
384                    (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
385                    (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
386                    (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
387                    (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
388                    (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
389                    (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
390
391
392         printf(_("Forest: %s\n"), reply.forest);
393         printf(_("Domain: %s\n"), reply.dns_domain);
394         printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
395
396         printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
397         printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
398
399         if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
400
401         printf(_("Server Site Name: %s\n"), reply.server_site);
402         printf(_("Client Site Name: %s\n"), reply.client_site);
403
404         d_printf(_("NT Version: %d\n"), reply.nt_version);
405         d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
406         d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
407
408         return 0;
409 }
410
411 /*
412   this implements the CLDAP based netlogon lookup requests
413   for finding the domain controller of a ADS domain
414 */
415 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
416 {
417         TALLOC_CTX *tmp_ctx = talloc_stackframe();
418         ADS_STRUCT *ads = NULL;
419         ADS_STATUS status;
420         int ret = -1;
421
422         if (c->display_usage) {
423                 d_printf("%s\n"
424                          "net ads lookup\n"
425                          "    %s",
426                          _("Usage:"),
427                          _("Find the ADS DC using CLDAP lookup.\n"));
428                 TALLOC_FREE(tmp_ctx);
429                 return 0;
430         }
431
432         status = ads_startup_nobind(c, false, tmp_ctx, &ads);
433         if (!ADS_ERR_OK(status)) {
434                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
435                 goto out;
436         }
437
438         if (!ads->config.realm) {
439                 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
440                 ads->ldap.port = 389;
441         }
442
443         ret = net_ads_cldap_netlogon(c, ads);
444 out:
445         ads_destroy(&ads);
446         TALLOC_FREE(tmp_ctx);
447         return ret;
448 }
449
450
451 #ifdef HAVE_JANSSON
452
453 static int net_ads_info_json(ADS_STRUCT *ads)
454 {
455         int ret = 0;
456         char addr[INET6_ADDRSTRLEN];
457         time_t pass_time;
458         struct json_object jsobj = json_new_object();
459
460         if (json_is_invalid(&jsobj)) {
461                 d_fprintf(stderr, _("error setting up JSON value\n"));
462
463                 goto failure;
464         }
465
466         pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
467
468         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
469
470         ret = json_add_string (&jsobj, "LDAP server", addr);
471         if (ret != 0) {
472                 goto failure;
473         }
474
475         ret = json_add_string (&jsobj, "LDAP server name",
476                                ads->config.ldap_server_name);
477         if (ret != 0) {
478                 goto failure;
479         }
480
481         ret = json_add_string (&jsobj, "Realm", ads->config.realm);
482         if (ret != 0) {
483                 goto failure;
484         }
485
486         ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
487         if (ret != 0) {
488                 goto failure;
489         }
490
491         ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
492         if (ret != 0) {
493                 goto failure;
494         }
495
496         ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
497         if (ret != 0) {
498                 goto failure;
499         }
500
501         ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
502         if (ret != 0) {
503                 goto failure;
504         }
505
506         ret = json_add_int (&jsobj, "Server time offset",
507                             ads->auth.time_offset);
508         if (ret != 0) {
509                 goto failure;
510         }
511
512         ret = json_add_int (&jsobj, "Last machine account password change",
513                             pass_time);
514         if (ret != 0) {
515                 goto failure;
516         }
517
518         ret = output_json(&jsobj);
519 failure:
520         json_free(&jsobj);
521
522         return ret;
523 }
524
525 #else /* [HAVE_JANSSON] */
526
527 static int net_ads_info_json(ADS_STRUCT *ads)
528 {
529         d_fprintf(stderr, _("JSON support not available\n"));
530
531         return -1;
532 }
533
534 #endif /* [HAVE_JANSSON] */
535
536
537
538 static int net_ads_info(struct net_context *c, int argc, const char **argv)
539 {
540         TALLOC_CTX *tmp_ctx = talloc_stackframe();
541         ADS_STRUCT *ads = NULL;
542         ADS_STATUS status;
543         char addr[INET6_ADDRSTRLEN];
544         time_t pass_time;
545         int ret = -1;
546
547         if (c->display_usage) {
548                 d_printf("%s\n"
549                          "net ads info\n"
550                          "    %s",
551                          _("Usage:"),
552                          _("Display information about an Active Directory "
553                            "server.\n"));
554                 TALLOC_FREE(tmp_ctx);
555                 return 0;
556         }
557
558         status = ads_startup_nobind(c, false, tmp_ctx, &ads);
559         if (!ADS_ERR_OK(status)) {
560                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
561                 goto out;
562         }
563
564         if (!ads || !ads->config.realm) {
565                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
566                 goto out;
567         }
568
569         /* Try to set the server's current time since we didn't do a full
570            TCP LDAP session initially */
571
572         if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
573                 d_fprintf( stderr, _("Failed to get server's current time!\n"));
574         }
575
576         if (c->opt_json) {
577                 ret = net_ads_info_json(ads);
578                 goto out;
579         }
580
581         pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
582
583         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
584
585         d_printf(_("LDAP server: %s\n"), addr);
586         d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
587         d_printf(_("Realm: %s\n"), ads->config.realm);
588         d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
589         d_printf(_("LDAP port: %d\n"), ads->ldap.port);
590         d_printf(_("Server time: %s\n"),
591                          http_timestring(tmp_ctx, ads->config.current_time));
592
593         d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
594         d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
595
596         d_printf(_("Last machine account password change: %s\n"),
597                  http_timestring(tmp_ctx, pass_time));
598
599         ret = 0;
600 out:
601         ads_destroy(&ads);
602         TALLOC_FREE(tmp_ctx);
603         return ret;
604 }
605
606 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
607                                   uint32_t auth_flags, ADS_STRUCT **ads_ret)
608 {
609         ADS_STRUCT *ads = NULL;
610         ADS_STATUS status;
611         bool need_password = false;
612         bool second_time = false;
613         char *cp;
614         const char *realm = NULL;
615         bool tried_closest_dc = false;
616         enum credentials_use_kerberos krb5_state =
617                 CRED_USE_KERBEROS_DISABLED;
618
619         /* lp_realm() should be handled by a command line param,
620            However, the join requires that realm be set in smb.conf
621            and compares our realm with the remote server's so this is
622            ok until someone needs more flexibility */
623
624         *ads_ret = NULL;
625
626 retry_connect:
627         if (only_own_domain) {
628                 realm = lp_realm();
629         } else {
630                 realm = assume_own_realm(c);
631         }
632
633         ads = ads_init(realm,
634                         c->opt_target_workgroup,
635                         c->opt_host,
636                         ADS_SASL_PLAIN);
637
638         if (!c->opt_user_name) {
639                 c->opt_user_name = "administrator";
640         }
641
642         if (c->opt_user_specified) {
643                 need_password = true;
644         }
645
646 retry:
647         if (!c->opt_password && need_password && !c->opt_machine_pass) {
648                 c->opt_password = net_prompt_pass(c, c->opt_user_name);
649                 if (!c->opt_password) {
650                         ads_destroy(&ads);
651                         return ADS_ERROR(LDAP_NO_MEMORY);
652                 }
653         }
654
655         if (c->opt_password) {
656                 use_in_memory_ccache();
657                 SAFE_FREE(ads->auth.password);
658                 ads->auth.password = smb_xstrdup(c->opt_password);
659         }
660
661         SAFE_FREE(ads->auth.user_name);
662         ads->auth.user_name = smb_xstrdup(c->opt_user_name);
663
664         ads->auth.flags |= auth_flags;
665
666         /* The ADS code will handle FIPS mode */
667         krb5_state = cli_credentials_get_kerberos_state(c->creds);
668         switch (krb5_state) {
669         case CRED_USE_KERBEROS_REQUIRED:
670                 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
671                 ads->auth.flags &= ~ADS_AUTH_ALLOW_NTLMSSP;
672                 break;
673         case CRED_USE_KERBEROS_DESIRED:
674                 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
675                 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
676                 break;
677         case CRED_USE_KERBEROS_DISABLED:
678                 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
679                 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
680                 break;
681         }
682
683        /*
684         * If the username is of the form "name@realm",
685         * extract the realm and convert to upper case.
686         * This is only used to establish the connection.
687         */
688        if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
689                 *cp++ = '\0';
690                 SAFE_FREE(ads->auth.realm);
691                 ads->auth.realm = smb_xstrdup(cp);
692                 if (!strupper_m(ads->auth.realm)) {
693                         ads_destroy(&ads);
694                         return ADS_ERROR(LDAP_NO_MEMORY);
695                 }
696        }
697
698         status = ads_connect(ads);
699
700         if (!ADS_ERR_OK(status)) {
701
702                 if (NT_STATUS_EQUAL(ads_ntstatus(status),
703                                     NT_STATUS_NO_LOGON_SERVERS)) {
704                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
705                         ads_destroy(&ads);
706                         return status;
707                 }
708
709                 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
710                         need_password = true;
711                         second_time = true;
712                         goto retry;
713                 } else {
714                         ads_destroy(&ads);
715                         return status;
716                 }
717         }
718
719         /* when contacting our own domain, make sure we use the closest DC.
720          * This is done by reconnecting to ADS because only the first call to
721          * ads_connect will give us our own sitename */
722
723         if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
724
725                 tried_closest_dc = true; /* avoid loop */
726
727                 if (!ads_closest_dc(ads)) {
728
729                         namecache_delete(ads->server.realm, 0x1C);
730                         namecache_delete(ads->server.workgroup, 0x1C);
731
732                         ads_destroy(&ads);
733                         ads = NULL;
734
735                         goto retry_connect;
736                 }
737         }
738
739         *ads_ret = ads;
740         return status;
741 }
742
743 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
744 {
745         return ads_startup_int(c, only_own_domain, 0, ads);
746 }
747
748 ADS_STATUS ads_startup_nobind(struct net_context *c,
749                               bool only_own_domain,
750                               TALLOC_CTX *mem_ctx,
751                               ADS_STRUCT **ads)
752 {
753         return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
754 }
755
756 /*
757   Check to see if connection can be made via ads.
758   ads_startup() stores the password in opt_password if it needs to so
759   that rpc or rap can use it without re-prompting.
760 */
761 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
762 {
763         ADS_STRUCT *ads;
764         ADS_STATUS status;
765
766         ads = ads_init(realm, workgroup, host, ADS_SASL_PLAIN);
767         if (ads == NULL ) {
768                 return -1;
769         }
770
771         ads->auth.flags |= ADS_AUTH_NO_BIND;
772
773         status = ads_connect(ads);
774         if ( !ADS_ERR_OK(status) ) {
775                 return -1;
776         }
777
778         ads_destroy(&ads);
779         return 0;
780 }
781
782 int net_ads_check_our_domain(struct net_context *c)
783 {
784         return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
785 }
786
787 int net_ads_check(struct net_context *c)
788 {
789         return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
790 }
791
792 /*
793    determine the netbios workgroup name for a domain
794  */
795 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
796 {
797         TALLOC_CTX *tmp_ctx = talloc_stackframe();
798         ADS_STRUCT *ads = NULL;
799         ADS_STATUS status;
800         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
801         bool ok = false;
802         int ret = -1;
803
804         if (c->display_usage) {
805                 d_printf  ("%s\n"
806                            "net ads workgroup\n"
807                            "    %s\n",
808                          _("Usage:"),
809                          _("Print the workgroup name"));
810                 TALLOC_FREE(tmp_ctx);
811                 return 0;
812         }
813
814         status = ads_startup_nobind(c, false, tmp_ctx, &ads);
815         if (!ADS_ERR_OK(status)) {
816                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
817                 goto out;
818         }
819
820         if (!ads->config.realm) {
821                 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
822                 ads->ldap.port = 389;
823         }
824
825         ok = ads_cldap_netlogon_5(tmp_ctx,
826                                   &ads->ldap.ss, ads->server.realm, &reply);
827         if (!ok) {
828                 d_fprintf(stderr, _("CLDAP query failed!\n"));
829                 goto out;
830         }
831
832         d_printf(_("Workgroup: %s\n"), reply.domain_name);
833
834         ret = 0;
835 out:
836         ads_destroy(&ads);
837         TALLOC_FREE(tmp_ctx);
838
839         return ret;
840 }
841
842
843
844 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
845 {
846         char **disp_fields = (char **) data_area;
847
848         if (!field) { /* must be end of record */
849                 if (disp_fields[0]) {
850                         if (!strchr_m(disp_fields[0], '$')) {
851                                 if (disp_fields[1])
852                                         d_printf("%-21.21s %s\n",
853                                                disp_fields[0], disp_fields[1]);
854                                 else
855                                         d_printf("%s\n", disp_fields[0]);
856                         }
857                 }
858                 SAFE_FREE(disp_fields[0]);
859                 SAFE_FREE(disp_fields[1]);
860                 return true;
861         }
862         if (!values) /* must be new field, indicate string field */
863                 return true;
864         if (strcasecmp_m(field, "sAMAccountName") == 0) {
865                 disp_fields[0] = SMB_STRDUP((char *) values[0]);
866         }
867         if (strcasecmp_m(field, "description") == 0)
868                 disp_fields[1] = SMB_STRDUP((char *) values[0]);
869         return true;
870 }
871
872 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
873 {
874         return net_user_usage(c, argc, argv);
875 }
876
877 static int ads_user_add(struct net_context *c, int argc, const char **argv)
878 {
879         TALLOC_CTX *tmp_ctx = talloc_stackframe();
880         ADS_STRUCT *ads = NULL;
881         ADS_STATUS status;
882         char *upn, *userdn;
883         LDAPMessage *res=NULL;
884         int rc = -1;
885         char *ou_str = NULL;
886
887         if (argc < 1 || c->display_usage) {
888                 TALLOC_FREE(tmp_ctx);
889                 return net_ads_user_usage(c, argc, argv);
890         }
891
892         status = ads_startup(c, false, &ads);
893         if (!ADS_ERR_OK(status)) {
894                 goto done;
895         }
896
897         status = ads_find_user_acct(ads, &res, argv[0]);
898         if (!ADS_ERR_OK(status)) {
899                 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
900                 goto done;
901         }
902
903         if (ads_count_replies(ads, res)) {
904                 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
905                           argv[0]);
906                 goto done;
907         }
908
909         if (c->opt_container) {
910                 ou_str = SMB_STRDUP(c->opt_container);
911         } else {
912                 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
913         }
914
915         status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
916         if (!ADS_ERR_OK(status)) {
917                 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
918                          ads_errstr(status));
919                 goto done;
920         }
921
922         /* if no password is to be set, we're done */
923         if (argc == 1) {
924                 d_printf(_("User %s added\n"), argv[0]);
925                 rc = 0;
926                 goto done;
927         }
928
929         /* try setting the password */
930         upn = talloc_asprintf(tmp_ctx,
931                               "%s@%s",
932                               argv[0],
933                               ads->config.realm);
934         if (upn == NULL) {
935                 goto done;
936         }
937
938         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
939                                        ads->auth.time_offset);
940         if (ADS_ERR_OK(status)) {
941                 d_printf(_("User %s added\n"), argv[0]);
942                 rc = 0;
943                 goto done;
944         }
945         TALLOC_FREE(upn);
946
947         /* password didn't set, delete account */
948         d_fprintf(stderr, _("Could not add user %s. "
949                             "Error setting password %s\n"),
950                  argv[0], ads_errstr(status));
951
952         ads_msgfree(ads, res);
953         res = NULL;
954
955         status=ads_find_user_acct(ads, &res, argv[0]);
956         if (ADS_ERR_OK(status)) {
957                 userdn = ads_get_dn(ads, tmp_ctx, res);
958                 ads_del_dn(ads, userdn);
959                 TALLOC_FREE(userdn);
960         }
961
962  done:
963         ads_msgfree(ads, res);
964         ads_destroy(&ads);
965         SAFE_FREE(ou_str);
966         TALLOC_FREE(tmp_ctx);
967         return rc;
968 }
969
970 static int ads_user_info(struct net_context *c, int argc, const char **argv)
971 {
972         TALLOC_CTX *tmp_ctx = talloc_stackframe();
973         ADS_STRUCT *ads = NULL;
974         ADS_STATUS status;
975         LDAPMessage *res = NULL;
976         int ret = -1;
977         wbcErr wbc_status;
978         const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
979         char *searchstring = NULL;
980         char **grouplist = NULL;
981         char *primary_group = NULL;
982         char *escaped_user = NULL;
983         struct dom_sid primary_group_sid;
984         uint32_t group_rid;
985         enum wbcSidType type;
986
987         if (argc < 1 || c->display_usage) {
988                 TALLOC_FREE(tmp_ctx);
989                 return net_ads_user_usage(c, argc, argv);
990         }
991
992         escaped_user = escape_ldap_string(tmp_ctx, argv[0]);
993         if (!escaped_user) {
994                 d_fprintf(stderr,
995                           _("ads_user_info: failed to escape user %s\n"),
996                           argv[0]);
997                 goto out;
998         }
999
1000         status = ads_startup(c, false, &ads);
1001         if (!ADS_ERR_OK(status)) {
1002                 goto out;
1003         }
1004
1005         searchstring = talloc_asprintf(tmp_ctx,
1006                                        "(sAMAccountName=%s)",
1007                                        escaped_user);
1008         if (searchstring == NULL) {
1009                 goto out;
1010         }
1011
1012         status = ads_search(ads, &res, searchstring, attrs);
1013         if (!ADS_ERR_OK(status)) {
1014                 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(status));
1015                 goto out;
1016         }
1017
1018         if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1019                 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
1020                 goto out;
1021         }
1022
1023         status = ads_domain_sid(ads, &primary_group_sid);
1024         if (!ADS_ERR_OK(status)) {
1025                 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(status));
1026                 goto out;
1027         }
1028
1029         sid_append_rid(&primary_group_sid, group_rid);
1030
1031         wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
1032                                   NULL, /* don't look up domain */
1033                                   &primary_group,
1034                                   &type);
1035         if (!WBC_ERROR_IS_OK(wbc_status)) {
1036                 d_fprintf(stderr, "wbcLookupSid: %s\n",
1037                           wbcErrorString(wbc_status));
1038                 goto out;
1039         }
1040
1041         d_printf("%s\n", primary_group);
1042
1043         wbcFreeMemory(primary_group);
1044
1045         grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1046                                     (LDAPMessage *)res, "memberOf");
1047
1048         if (grouplist) {
1049                 int i;
1050                 char **groupname;
1051                 for (i=0;grouplist[i];i++) {
1052                         groupname = ldap_explode_dn(grouplist[i], 1);
1053                         d_printf("%s\n", groupname[0]);
1054                         ldap_value_free(groupname);
1055                 }
1056                 ldap_value_free(grouplist);
1057         }
1058
1059         ret = 0;
1060 out:
1061         ads_msgfree(ads, res);
1062         ads_destroy(&ads);
1063         TALLOC_FREE(tmp_ctx);
1064         return ret;
1065 }
1066
1067 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1068 {
1069         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1070         ADS_STRUCT *ads = NULL;
1071         ADS_STATUS status;
1072         LDAPMessage *res = NULL;
1073         char *userdn = NULL;
1074         int ret = -1;
1075
1076         if (argc < 1) {
1077                 TALLOC_FREE(tmp_ctx);
1078                 return net_ads_user_usage(c, argc, argv);
1079         }
1080
1081         status = ads_startup(c, false, &ads);
1082         if (!ADS_ERR_OK(status)) {
1083                 goto out;
1084         }
1085
1086         status = ads_find_user_acct(ads, &res, argv[0]);
1087         if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1088                 d_printf(_("User %s does not exist.\n"), argv[0]);
1089                 goto out;
1090         }
1091
1092         userdn = ads_get_dn(ads, tmp_ctx, res);
1093         if (userdn == NULL) {
1094                 goto out;
1095         }
1096
1097         status = ads_del_dn(ads, userdn);
1098         if (!ADS_ERR_OK(status)) {
1099                 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1100                           ads_errstr(status));
1101                 goto out;
1102         }
1103
1104         d_printf(_("User %s deleted\n"), argv[0]);
1105
1106         ret = 0;
1107 out:
1108         ads_msgfree(ads, res);
1109         ads_destroy(&ads);
1110         TALLOC_FREE(tmp_ctx);
1111         return ret;
1112 }
1113
1114 int net_ads_user(struct net_context *c, int argc, const char **argv)
1115 {
1116         struct functable func[] = {
1117                 {
1118                         "add",
1119                         ads_user_add,
1120                         NET_TRANSPORT_ADS,
1121                         N_("Add an AD user"),
1122                         N_("net ads user add\n"
1123                            "    Add an AD user")
1124                 },
1125                 {
1126                         "info",
1127                         ads_user_info,
1128                         NET_TRANSPORT_ADS,
1129                         N_("Display information about an AD user"),
1130                         N_("net ads user info\n"
1131                            "    Display information about an AD user")
1132                 },
1133                 {
1134                         "delete",
1135                         ads_user_delete,
1136                         NET_TRANSPORT_ADS,
1137                         N_("Delete an AD user"),
1138                         N_("net ads user delete\n"
1139                            "    Delete an AD user")
1140                 },
1141                 {NULL, NULL, 0, NULL, NULL}
1142         };
1143         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1144         ADS_STRUCT *ads = NULL;
1145         ADS_STATUS status;
1146         const char *shortattrs[] = {"sAMAccountName", NULL};
1147         const char *longattrs[] = {"sAMAccountName", "description", NULL};
1148         char *disp_fields[2] = {NULL, NULL};
1149         int ret = -1;
1150
1151         if (argc > 0) {
1152                 TALLOC_FREE(tmp_ctx);
1153                 return net_run_function(c, argc, argv, "net ads user", func);
1154         }
1155
1156         if (c->display_usage) {
1157                 d_printf(  "%s\n"
1158                            "net ads user\n"
1159                            "    %s\n",
1160                          _("Usage:"),
1161                          _("List AD users"));
1162                 net_display_usage_from_functable(func);
1163                 TALLOC_FREE(tmp_ctx);
1164                 return 0;
1165         }
1166
1167         status = ads_startup(c, false, &ads);
1168         if (!ADS_ERR_OK(status)) {
1169                 goto out;
1170         }
1171
1172         if (c->opt_long_list_entries)
1173                 d_printf(_("\nUser name             Comment"
1174                            "\n-----------------------------\n"));
1175
1176         status = ads_do_search_all_fn(ads,
1177                                       ads->config.bind_path,
1178                                       LDAP_SCOPE_SUBTREE,
1179                                       "(objectCategory=user)",
1180                                       c->opt_long_list_entries ?
1181                                               longattrs : shortattrs,
1182                                       usergrp_display,
1183                                       disp_fields);
1184         if (!ADS_ERR_OK(status)) {
1185                 goto out;
1186         }
1187
1188         ret = 0;
1189 out:
1190         ads_destroy(&ads);
1191         TALLOC_FREE(tmp_ctx);
1192         return ret;
1193 }
1194
1195 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1196 {
1197         return net_group_usage(c, argc, argv);
1198 }
1199
1200 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1201 {
1202         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1203         ADS_STRUCT *ads = NULL;
1204         ADS_STATUS status;
1205         LDAPMessage *res = NULL;
1206         int ret = -1;
1207         char *ou_str = NULL;
1208
1209         if (argc < 1 || c->display_usage) {
1210                 TALLOC_FREE(tmp_ctx);
1211                 return net_ads_group_usage(c, argc, argv);
1212         }
1213
1214         status = ads_startup(c, false, &ads);
1215         if (!ADS_ERR_OK(status)) {
1216                 goto out;
1217         }
1218
1219         status = ads_find_user_acct(ads, &res, argv[0]);
1220         if (!ADS_ERR_OK(status)) {
1221                 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1222                 goto out;
1223         }
1224
1225         if (ads_count_replies(ads, res)) {
1226                 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1227                 goto out;
1228         }
1229
1230         if (c->opt_container) {
1231                 ou_str = SMB_STRDUP(c->opt_container);
1232         } else {
1233                 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1234         }
1235
1236         status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1237         if (!ADS_ERR_OK(status)) {
1238                 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1239                           ads_errstr(status));
1240                 goto out;
1241         }
1242
1243         d_printf(_("Group %s added\n"), argv[0]);
1244
1245         ret = 0;
1246  out:
1247         ads_msgfree(ads, res);
1248         ads_destroy(&ads);
1249         SAFE_FREE(ou_str);
1250         TALLOC_FREE(tmp_ctx);
1251         return ret;
1252 }
1253
1254 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1255 {
1256         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1257         ADS_STRUCT *ads = NULL;
1258         ADS_STATUS status;
1259         LDAPMessage *res = NULL;
1260         char *groupdn = NULL;
1261         int ret = -1;
1262
1263         if (argc < 1 || c->display_usage) {
1264                 TALLOC_FREE(tmp_ctx);
1265                 return net_ads_group_usage(c, argc, argv);
1266         }
1267
1268         status = ads_startup(c, false, &ads);
1269         if (!ADS_ERR_OK(status)) {
1270                 goto out;
1271         }
1272
1273         status = ads_find_user_acct(ads, &res, argv[0]);
1274         if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1275                 d_printf(_("Group %s does not exist.\n"), argv[0]);
1276                 goto out;
1277         }
1278
1279         groupdn = ads_get_dn(ads, tmp_ctx, res);
1280         if (groupdn == NULL) {
1281                 goto out;
1282         }
1283
1284         status = ads_del_dn(ads, groupdn);
1285         if (!ADS_ERR_OK(status)) {
1286                 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1287                           ads_errstr(status));
1288                 goto out;
1289         }
1290         d_printf(_("Group %s deleted\n"), argv[0]);
1291
1292         ret = 0;
1293 out:
1294         ads_msgfree(ads, res);
1295         ads_destroy(&ads);
1296         TALLOC_FREE(tmp_ctx);
1297         return ret;
1298 }
1299
1300 int net_ads_group(struct net_context *c, int argc, const char **argv)
1301 {
1302         struct functable func[] = {
1303                 {
1304                         "add",
1305                         ads_group_add,
1306                         NET_TRANSPORT_ADS,
1307                         N_("Add an AD group"),
1308                         N_("net ads group add\n"
1309                            "    Add an AD group")
1310                 },
1311                 {
1312                         "delete",
1313                         ads_group_delete,
1314                         NET_TRANSPORT_ADS,
1315                         N_("Delete an AD group"),
1316                         N_("net ads group delete\n"
1317                            "    Delete an AD group")
1318                 },
1319                 {NULL, NULL, 0, NULL, NULL}
1320         };
1321         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1322         ADS_STRUCT *ads = NULL;
1323         ADS_STATUS status;
1324         const char *shortattrs[] = {"sAMAccountName", NULL};
1325         const char *longattrs[] = {"sAMAccountName", "description", NULL};
1326         char *disp_fields[2] = {NULL, NULL};
1327         int ret = -1;
1328
1329         if (argc >= 0) {
1330                 TALLOC_FREE(tmp_ctx);
1331                 return net_run_function(c, argc, argv, "net ads group", func);
1332         }
1333
1334         if (c->display_usage) {
1335                 d_printf(  "%s\n"
1336                            "net ads group\n"
1337                            "    %s\n",
1338                          _("Usage:"),
1339                          _("List AD groups"));
1340                 net_display_usage_from_functable(func);
1341                 TALLOC_FREE(tmp_ctx);
1342                 return 0;
1343         }
1344
1345         status = ads_startup(c, false, &ads);
1346         if (!ADS_ERR_OK(status)) {
1347                 goto out;
1348         }
1349
1350         if (c->opt_long_list_entries)
1351                 d_printf(_("\nGroup name            Comment"
1352                            "\n-----------------------------\n"));
1353
1354         status = ads_do_search_all_fn(ads,
1355                                       ads->config.bind_path,
1356                                       LDAP_SCOPE_SUBTREE,
1357                                       "(objectCategory=group)",
1358                                       c->opt_long_list_entries ?
1359                                               longattrs : shortattrs,
1360                                       usergrp_display,
1361                                       disp_fields);
1362         if (!ADS_ERR_OK(status)) {
1363                 goto out;
1364         }
1365
1366         ret = 0;
1367 out:
1368         ads_destroy(&ads);
1369         TALLOC_FREE(tmp_ctx);
1370         return ret;
1371 }
1372
1373 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1374 {
1375         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1376         ADS_STRUCT *ads = NULL;
1377         ADS_STATUS status;
1378         LDAPMessage *res = NULL;
1379         int ret = -1;
1380
1381         if (c->display_usage) {
1382                 d_printf(  "%s\n"
1383                            "net ads status\n"
1384                            "    %s\n",
1385                          _("Usage:"),
1386                          _("Display machine account details"));
1387                 TALLOC_FREE(tmp_ctx);
1388                 return 0;
1389         }
1390
1391         status = ads_startup(c, true, &ads);
1392         if (!ADS_ERR_OK(status)) {
1393                 goto out;
1394         }
1395
1396         status = ads_find_machine_acct(ads, &res, lp_netbios_name());
1397         if (!ADS_ERR_OK(status)) {
1398                 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"),
1399                           ads_errstr(status));
1400                 goto out;
1401         }
1402
1403         if (ads_count_replies(ads, res) == 0) {
1404                 d_fprintf(stderr, _("No machine account for '%s' found\n"),
1405                           lp_netbios_name());
1406                 goto out;
1407         }
1408
1409         ads_dump(ads, res);
1410
1411         ret = 0;
1412 out:
1413         ads_msgfree(ads, res);
1414         ads_destroy(&ads);
1415         TALLOC_FREE(tmp_ctx);
1416         return ret;
1417 }
1418
1419 /*******************************************************************
1420  Leave an AD domain.  Windows XP disables the machine account.
1421  We'll try the same.  The old code would do an LDAP delete.
1422  That only worked using the machine creds because added the machine
1423  with full control to the computer object's ACL.
1424 *******************************************************************/
1425
1426 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1427 {
1428         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1429         struct libnet_UnjoinCtx *r = NULL;
1430         WERROR werr;
1431         int ret = -1;
1432
1433         if (c->display_usage) {
1434                 d_printf(  "%s\n"
1435                            "net ads leave [--keep-account]\n"
1436                            "    %s\n",
1437                          _("Usage:"),
1438                          _("Leave an AD domain"));
1439                 TALLOC_FREE(tmp_ctx);
1440                 return 0;
1441         }
1442
1443         if (!*lp_realm()) {
1444                 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1445                 TALLOC_FREE(tmp_ctx);
1446                 return -1;
1447         }
1448
1449         if (!c->opt_kerberos) {
1450                 use_in_memory_ccache();
1451         }
1452
1453         if (!c->msg_ctx) {
1454                 d_fprintf(stderr, _("Could not initialise message context. "
1455                         "Try running as root\n"));
1456                 goto done;
1457         }
1458
1459         werr = libnet_init_UnjoinCtx(tmp_ctx, &r);
1460         if (!W_ERROR_IS_OK(werr)) {
1461                 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1462                 goto done;
1463         }
1464
1465         r->in.debug             = true;
1466         r->in.use_kerberos      = c->opt_kerberos;
1467         r->in.dc_name           = c->opt_host;
1468         r->in.domain_name       = lp_realm();
1469         r->in.admin_account     = c->opt_user_name;
1470         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1471         r->in.modify_config     = lp_config_backend_is_registry();
1472
1473         /* Try to delete it, but if that fails, disable it.  The
1474            WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1475         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1476                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1477         if (c->opt_keep_account) {
1478                 r->in.delete_machine_account = false;
1479         } else {
1480                 r->in.delete_machine_account = true;
1481         }
1482
1483         r->in.msg_ctx           = c->msg_ctx;
1484
1485         werr = libnet_Unjoin(tmp_ctx, r);
1486         if (!W_ERROR_IS_OK(werr)) {
1487                 d_printf(_("Failed to leave domain: %s\n"),
1488                          r->out.error_string ? r->out.error_string :
1489                          get_friendly_werror_msg(werr));
1490                 goto done;
1491         }
1492
1493         if (r->out.deleted_machine_account) {
1494                 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1495                         r->in.machine_name, r->out.dns_domain_name);
1496                 ret = 0;
1497                 goto done;
1498         }
1499
1500         /* We couldn't delete it - see if the disable succeeded. */
1501         if (r->out.disabled_machine_account) {
1502                 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1503                         r->in.machine_name, r->out.dns_domain_name);
1504                 ret = 0;
1505                 goto done;
1506         }
1507
1508         /* Based on what we requested, we shouldn't get here, but if
1509            we did, it means the secrets were removed, and therefore
1510            we have left the domain */
1511         d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1512                   r->in.machine_name, r->out.dns_domain_name);
1513
1514         ret = 0;
1515  done:
1516         TALLOC_FREE(tmp_ctx);
1517         return ret;
1518 }
1519
1520 static ADS_STATUS net_ads_join_ok(struct net_context *c)
1521 {
1522         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1523         ADS_STRUCT *ads = NULL;
1524         ADS_STATUS status;
1525         fstring dc_name;
1526         struct sockaddr_storage dcip;
1527
1528         if (!secrets_init()) {
1529                 DEBUG(1,("Failed to initialise secrets database\n"));
1530                 TALLOC_FREE(tmp_ctx);
1531                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1532         }
1533
1534         net_use_krb_machine_account(c);
1535
1536         get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1537
1538         status = ads_startup(c, true, &ads);
1539         if (!ADS_ERR_OK(status)) {
1540                 goto out;
1541         }
1542
1543         status = ADS_ERROR_NT(NT_STATUS_OK);
1544 out:
1545         ads_destroy(&ads);
1546         TALLOC_FREE(tmp_ctx);
1547         return  status;
1548 }
1549
1550 /*
1551   check that an existing join is OK
1552  */
1553 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1554 {
1555         ADS_STATUS status;
1556         use_in_memory_ccache();
1557
1558         if (c->display_usage) {
1559                 d_printf(  "%s\n"
1560                            "net ads testjoin\n"
1561                            "    %s\n",
1562                          _("Usage:"),
1563                          _("Test if the existing join is ok"));
1564                 return 0;
1565         }
1566
1567         /* Display success or failure */
1568         status = net_ads_join_ok(c);
1569         if (!ADS_ERR_OK(status)) {
1570                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1571                         get_friendly_nt_error_msg(ads_ntstatus(status)));
1572                 return -1;
1573         }
1574
1575         printf(_("Join is OK\n"));
1576         return 0;
1577 }
1578
1579 /*******************************************************************
1580   Simple config checks before beginning the join
1581  ********************************************************************/
1582
1583 static WERROR check_ads_config( void )
1584 {
1585         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1586                 d_printf(_("Host is not configured as a member server.\n"));
1587                 return WERR_INVALID_DOMAIN_ROLE;
1588         }
1589
1590         if (strlen(lp_netbios_name()) > 15) {
1591                 d_printf(_("Our netbios name can be at most 15 chars long, "
1592                            "\"%s\" is %u chars long\n"), lp_netbios_name(),
1593                          (unsigned int)strlen(lp_netbios_name()));
1594                 return WERR_INVALID_COMPUTERNAME;
1595         }
1596
1597         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1598                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1599                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1600                 return WERR_INVALID_PARAMETER;
1601         }
1602
1603         return WERR_OK;
1604 }
1605
1606 /*******************************************************************
1607  ********************************************************************/
1608
1609 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1610 {
1611         d_printf(_("net ads join [--no-dns-updates] [options]\n"
1612                    "Valid options:\n"));
1613         d_printf(_("   dnshostname=FQDN      Set the dnsHostName attribute during the join.\n"
1614                    "                         The default is in the form netbiosname.dnsdomain\n"));
1615         d_printf(_("   createupn[=UPN]       Set the userPrincipalName attribute during the join.\n"
1616                    "                         The default UPN is in the form host/netbiosname@REALM.\n"));
1617         d_printf(_("   createcomputer=OU     Precreate the computer account in a specific OU.\n"
1618                    "                         The OU string read from top to bottom without RDNs\n"
1619                    "                         and delimited by a '/'.\n"
1620                    "                         E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1621                    "                         NB: A backslash '\\' is used as escape at multiple\n"
1622                    "                             levels and may need to be doubled or even\n"
1623                    "                             quadrupled. It is not used as a separator.\n"));
1624         d_printf(_("   machinepass=PASS      Set the machine password to a specific value during\n"
1625                    "                         the join. The default password is random.\n"));
1626         d_printf(_("   osName=string         Set the operatingSystem attribute during the join.\n"));
1627         d_printf(_("   osVer=string          Set the operatingSystemVersion attribute during join.\n"
1628                    "                         NB: osName and osVer must be specified together for\n"
1629                    "                             either to take effect. The operatingSystemService\n"
1630                    "                             attribute is then also set along with the two\n"
1631                    "                             other attributes.\n"));
1632         d_printf(_("   osServicePack=string  Set the operatingSystemServicePack attribute\n"
1633                    "                         during the join.\n"
1634                    "                         NB: If not specified then by default the samba\n"
1635                    "                             version string is used instead.\n"));
1636         return -1;
1637 }
1638
1639
1640 int net_ads_join(struct net_context *c, int argc, const char **argv)
1641 {
1642         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1643         struct libnet_JoinCtx *r = NULL;
1644         const char *domain = lp_realm();
1645         WERROR werr = WERR_NERR_SETUPNOTJOINED;
1646         bool createupn = false;
1647         const char *dnshostname = NULL;
1648         const char *machineupn = NULL;
1649         const char *machine_password = NULL;
1650         const char *create_in_ou = NULL;
1651         int i;
1652         const char *os_name = NULL;
1653         const char *os_version = NULL;
1654         const char *os_servicepack = NULL;
1655         bool modify_config = lp_config_backend_is_registry();
1656         enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1657         int ret = -1;
1658
1659         if (c->display_usage) {
1660                 TALLOC_FREE(tmp_ctx);
1661                 return net_ads_join_usage(c, argc, argv);
1662         }
1663
1664         if (!modify_config) {
1665                 werr = check_ads_config();
1666                 if (!W_ERROR_IS_OK(werr)) {
1667                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1668                         goto fail;
1669                 }
1670         }
1671
1672         if (!c->opt_kerberos) {
1673                 use_in_memory_ccache();
1674         }
1675
1676         werr = libnet_init_JoinCtx(tmp_ctx, &r);
1677         if (!W_ERROR_IS_OK(werr)) {
1678                 goto fail;
1679         }
1680
1681         /* process additional command line args */
1682
1683         for ( i=0; i<argc; i++ ) {
1684                 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1685                         dnshostname = get_string_param(argv[i]);
1686                 }
1687                 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1688                         createupn = true;
1689                         machineupn = get_string_param(argv[i]);
1690                 }
1691                 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1692                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1693                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1694                                 werr = WERR_INVALID_PARAMETER;
1695                                 goto fail;
1696                         }
1697                 }
1698                 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1699                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1700                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1701                                 werr = WERR_INVALID_PARAMETER;
1702                                 goto fail;
1703                         }
1704                 }
1705                 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1706                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1707                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1708                                 werr = WERR_INVALID_PARAMETER;
1709                                 goto fail;
1710                         }
1711                 }
1712                 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1713                         if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1714                                 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1715                                 werr = WERR_INVALID_PARAMETER;
1716                                 goto fail;
1717                         }
1718                 }
1719                 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1720                         if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1721                                 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1722                                 werr = WERR_INVALID_PARAMETER;
1723                                 goto fail;
1724                         }
1725                 } else {
1726                         domain = argv[i];
1727                         if (strchr(domain, '.') == NULL) {
1728                                 domain_name_type = JoinDomNameTypeUnknown;
1729                         } else {
1730                                 domain_name_type = JoinDomNameTypeDNS;
1731                         }
1732                 }
1733         }
1734
1735         if (!*domain) {
1736                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1737                 werr = WERR_INVALID_PARAMETER;
1738                 goto fail;
1739         }
1740
1741         if (!c->msg_ctx) {
1742                 d_fprintf(stderr, _("Could not initialise message context. "
1743                         "Try running as root\n"));
1744                 werr = WERR_ACCESS_DENIED;
1745                 goto fail;
1746         }
1747
1748         /* Do the domain join here */
1749
1750         r->in.domain_name       = domain;
1751         r->in.domain_name_type  = domain_name_type;
1752         r->in.create_upn        = createupn;
1753         r->in.upn               = machineupn;
1754         r->in.dnshostname       = dnshostname;
1755         r->in.account_ou        = create_in_ou;
1756         r->in.os_name           = os_name;
1757         r->in.os_version        = os_version;
1758         r->in.os_servicepack    = os_servicepack;
1759         r->in.dc_name           = c->opt_host;
1760         r->in.admin_account     = c->opt_user_name;
1761         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1762         r->in.machine_password  = machine_password;
1763         r->in.debug             = true;
1764         r->in.use_kerberos      = c->opt_kerberos;
1765         r->in.modify_config     = modify_config;
1766         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1767                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1768                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1769         r->in.msg_ctx           = c->msg_ctx;
1770
1771         werr = libnet_Join(tmp_ctx, r);
1772         if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1773             strequal(domain, lp_realm())) {
1774                 r->in.domain_name = lp_workgroup();
1775                 r->in.domain_name_type = JoinDomNameTypeNBT;
1776                 werr = libnet_Join(tmp_ctx, r);
1777         }
1778         if (!W_ERROR_IS_OK(werr)) {
1779                 goto fail;
1780         }
1781
1782         /* Check the short name of the domain */
1783
1784         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1785                 d_printf(_("The workgroup in %s does not match the short\n"
1786                            "domain name obtained from the server.\n"
1787                            "Using the name [%s] from the server.\n"
1788                            "You should set \"workgroup = %s\" in %s.\n"),
1789                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1790                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1791         }
1792
1793         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1794
1795         if (r->out.dns_domain_name) {
1796                 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1797                         r->out.dns_domain_name);
1798         } else {
1799                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1800                         r->out.netbios_domain_name);
1801         }
1802
1803         /* print out informative error string in case there is one */
1804         if (r->out.error_string != NULL) {
1805                 d_printf("%s\n", r->out.error_string);
1806         }
1807
1808         /*
1809          * We try doing the dns update (if it was compiled in
1810          * and if it was not disabled on the command line).
1811          * If the dns update fails, we still consider the join
1812          * operation as succeeded if we came this far.
1813          */
1814         if (!c->opt_no_dns_updates) {
1815                 net_ads_join_dns_updates(c, tmp_ctx, r);
1816         }
1817
1818         ret = 0;
1819
1820 fail:
1821         if (ret != 0) {
1822                 /* issue an overall failure message at the end. */
1823                 d_printf(_("Failed to join domain: %s\n"),
1824                         r && r->out.error_string ? r->out.error_string :
1825                         get_friendly_werror_msg(werr));
1826         }
1827
1828         TALLOC_FREE(tmp_ctx);
1829
1830         return ret;
1831 }
1832
1833 /*******************************************************************
1834  ********************************************************************/
1835
1836 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1837 {
1838 #if defined(HAVE_KRB5)
1839         ADS_STRUCT *ads;
1840         ADS_STATUS status;
1841         NTSTATUS ntstatus;
1842         TALLOC_CTX *ctx;
1843         const char *hostname = NULL;
1844         const char **addrs_list = NULL;
1845         struct sockaddr_storage *addrs = NULL;
1846         int num_addrs = 0;
1847         int count;
1848
1849 #ifdef DEVELOPER
1850         talloc_enable_leak_report();
1851 #endif
1852
1853         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1854                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1855                                     "detection of addresses in a clustered "
1856                                     "setup.\n"));
1857                 c->display_usage = true;
1858         }
1859
1860         if (c->display_usage) {
1861                 d_printf(  "%s\n"
1862                            "net ads dns register [hostname [IP [IP...]]]\n"
1863                            "    %s\n",
1864                          _("Usage:"),
1865                          _("Register hostname with DNS\n"));
1866                 return -1;
1867         }
1868
1869         if (!(ctx = talloc_init("net_ads_dns"))) {
1870                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1871                 return -1;
1872         }
1873
1874         if (argc >= 1) {
1875                 hostname = argv[0];
1876         }
1877
1878         if (argc > 1) {
1879                 num_addrs = argc - 1;
1880                 addrs_list = &argv[1];
1881         } else if (lp_clustering()) {
1882                 addrs_list = lp_cluster_addresses();
1883                 num_addrs = str_list_length(addrs_list);
1884         }
1885
1886         if (num_addrs > 0) {
1887                 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1888                 if (addrs == NULL) {
1889                         d_fprintf(stderr, _("Error allocating memory!\n"));
1890                         talloc_free(ctx);
1891                         return -1;
1892                 }
1893         }
1894
1895         for (count = 0; count < num_addrs; count++) {
1896                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1897                         d_fprintf(stderr, "%s '%s'.\n",
1898                                           _("Cannot interpret address"),
1899                                           addrs_list[count]);
1900                         talloc_free(ctx);
1901                         return -1;
1902                 }
1903         }
1904
1905         status = ads_startup(c, true, &ads);
1906         if ( !ADS_ERR_OK(status) ) {
1907                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1908                 TALLOC_FREE(ctx);
1909                 return -1;
1910         }
1911
1912         ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1913         if (!NT_STATUS_IS_OK(ntstatus)) {
1914                 d_fprintf( stderr, _("DNS update failed!\n") );
1915                 ads_destroy( &ads );
1916                 TALLOC_FREE( ctx );
1917                 return -1;
1918         }
1919
1920         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1921
1922         ads_destroy(&ads);
1923         TALLOC_FREE( ctx );
1924
1925         return 0;
1926 #else
1927         d_fprintf(stderr,
1928                   _("DNS update support not enabled at compile time!\n"));
1929         return -1;
1930 #endif
1931 }
1932
1933 static int net_ads_dns_unregister(struct net_context *c,
1934                                   int argc,
1935                                   const char **argv)
1936 {
1937 #if defined(HAVE_KRB5)
1938         ADS_STRUCT *ads;
1939         ADS_STATUS status;
1940         NTSTATUS ntstatus;
1941         TALLOC_CTX *ctx;
1942         const char *hostname = NULL;
1943
1944 #ifdef DEVELOPER
1945         talloc_enable_leak_report();
1946 #endif
1947
1948         if (argc != 1) {
1949                 c->display_usage = true;
1950         }
1951
1952         if (c->display_usage) {
1953                 d_printf(  "%s\n"
1954                            "net ads dns unregister [hostname]\n"
1955                            "    %s\n",
1956                          _("Usage:"),
1957                          _("Remove all IP Address entires for a given\n"
1958                            "    hostname from the Active Directory server.\n"));
1959                 return -1;
1960         }
1961
1962         if (!(ctx = talloc_init("net_ads_dns"))) {
1963                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1964                 return -1;
1965         }
1966
1967         /* Get the hostname for un-registering */
1968         hostname = argv[0];
1969
1970         status = ads_startup(c, true, &ads);
1971         if ( !ADS_ERR_OK(status) ) {
1972                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1973                 TALLOC_FREE(ctx);
1974                 return -1;
1975         }
1976
1977         ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1978         if (!NT_STATUS_IS_OK(ntstatus)) {
1979                 d_fprintf( stderr, _("DNS update failed!\n") );
1980                 ads_destroy( &ads );
1981                 TALLOC_FREE( ctx );
1982                 return -1;
1983         }
1984
1985         d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1986
1987         ads_destroy(&ads);
1988         TALLOC_FREE( ctx );
1989
1990         return 0;
1991 #else
1992         d_fprintf(stderr,
1993                   _("DNS update support not enabled at compile time!\n"));
1994         return -1;
1995 #endif
1996 }
1997
1998
1999 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2000 {
2001         size_t num_names = 0;
2002         char **hostnames = NULL;
2003         size_t i = 0;
2004         struct samba_sockaddr *addrs = NULL;
2005         NTSTATUS status;
2006
2007         if (argc != 1 || c->display_usage) {
2008                 d_printf(  "%s\n"
2009                            "    %s\n"
2010                            "    %s\n",
2011                          _("Usage:"),
2012                          _("net ads dns async <name>\n"),
2013                          _("  Async look up hostname from the DNS server\n"
2014                            "    hostname\tName to look up\n"));
2015                 return -1;
2016         }
2017
2018         status = ads_dns_lookup_a(talloc_tos(),
2019                                   argv[0],
2020                                   &num_names,
2021                                   &hostnames,
2022                                   &addrs);
2023         if (!NT_STATUS_IS_OK(status)) {
2024                 d_printf("Looking up A record for %s got error %s\n",
2025                          argv[0],
2026                          nt_errstr(status));
2027                 return -1;
2028         }
2029         d_printf("Async A record lookup - got %u names for %s\n",
2030                  (unsigned int)num_names,
2031                  argv[0]);
2032         for (i = 0; i < num_names; i++) {
2033                 char addr_buf[INET6_ADDRSTRLEN];
2034                 print_sockaddr(addr_buf,
2035                                sizeof(addr_buf),
2036                                &addrs[i].u.ss);
2037                 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2038                         (unsigned int)i,
2039                         hostnames[i],
2040                         addr_buf);
2041         }
2042
2043 #if defined(HAVE_IPV6)
2044         status = ads_dns_lookup_aaaa(talloc_tos(),
2045                                      argv[0],
2046                                      &num_names,
2047                                      &hostnames,
2048                                      &addrs);
2049         if (!NT_STATUS_IS_OK(status)) {
2050                 d_printf("Looking up AAAA record for %s got error %s\n",
2051                          argv[0],
2052                          nt_errstr(status));
2053                 return -1;
2054         }
2055         d_printf("Async AAAA record lookup - got %u names for %s\n",
2056                  (unsigned int)num_names,
2057                  argv[0]);
2058         for (i = 0; i < num_names; i++) {
2059                 char addr_buf[INET6_ADDRSTRLEN];
2060                 print_sockaddr(addr_buf,
2061                                sizeof(addr_buf),
2062                                &addrs[i].u.ss);
2063                 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2064                         (unsigned int)i,
2065                         hostnames[i],
2066                         addr_buf);
2067         }
2068 #endif
2069         return 0;
2070 }
2071
2072
2073 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2074 {
2075         struct functable func[] = {
2076                 {
2077                         "register",
2078                         net_ads_dns_register,
2079                         NET_TRANSPORT_ADS,
2080                         N_("Add host dns entry to AD"),
2081                         N_("net ads dns register\n"
2082                            "    Add host dns entry to AD")
2083                 },
2084                 {
2085                         "unregister",
2086                         net_ads_dns_unregister,
2087                         NET_TRANSPORT_ADS,
2088                         N_("Remove host dns entry from AD"),
2089                         N_("net ads dns unregister\n"
2090                            "    Remove host dns entry from AD")
2091                 },
2092                 {
2093                         "async",
2094                         net_ads_dns_async,
2095                         NET_TRANSPORT_ADS,
2096                         N_("Look up host"),
2097                         N_("net ads dns async\n"
2098                            "    Look up host using async DNS")
2099                 },
2100                 {NULL, NULL, 0, NULL, NULL}
2101         };
2102
2103         return net_run_function(c, argc, argv, "net ads dns", func);
2104 }
2105
2106 /*******************************************************************
2107  ********************************************************************/
2108
2109 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2110 {
2111         d_printf(_(
2112 "\nnet ads printer search <printer>"
2113 "\n\tsearch for a printer in the directory\n"
2114 "\nnet ads printer info <printer> <server>"
2115 "\n\tlookup info in directory for printer on server"
2116 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2117 "\nnet ads printer publish <printername>"
2118 "\n\tpublish printer in directory"
2119 "\n\t(note: printer name is required)\n"
2120 "\nnet ads printer remove <printername>"
2121 "\n\tremove printer from directory"
2122 "\n\t(note: printer name is required)\n"));
2123         return -1;
2124 }
2125
2126 /*******************************************************************
2127  ********************************************************************/
2128
2129 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2130 {
2131         ADS_STRUCT *ads;
2132         ADS_STATUS rc;
2133         LDAPMessage *res = NULL;
2134
2135         if (c->display_usage) {
2136                 d_printf(  "%s\n"
2137                            "net ads printer search\n"
2138                            "    %s\n",
2139                          _("Usage:"),
2140                          _("List printers in the AD"));
2141                 return 0;
2142         }
2143
2144         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2145                 return -1;
2146         }
2147
2148         rc = ads_find_printers(ads, &res);
2149
2150         if (!ADS_ERR_OK(rc)) {
2151                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2152                 ads_msgfree(ads, res);
2153                 ads_destroy(&ads);
2154                 return -1;
2155         }
2156
2157         if (ads_count_replies(ads, res) == 0) {
2158                 d_fprintf(stderr, _("No results found\n"));
2159                 ads_msgfree(ads, res);
2160                 ads_destroy(&ads);
2161                 return -1;
2162         }
2163
2164         ads_dump(ads, res);
2165         ads_msgfree(ads, res);
2166         ads_destroy(&ads);
2167         return 0;
2168 }
2169
2170 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2171 {
2172         ADS_STRUCT *ads;
2173         ADS_STATUS rc;
2174         const char *servername, *printername;
2175         LDAPMessage *res = NULL;
2176
2177         if (c->display_usage) {
2178                 d_printf("%s\n%s",
2179                          _("Usage:"),
2180                          _("net ads printer info [printername [servername]]\n"
2181                            "  Display printer info from AD\n"
2182                            "    printername\tPrinter name or wildcard\n"
2183                            "    servername\tName of the print server\n"));
2184                 return 0;
2185         }
2186
2187         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2188                 return -1;
2189         }
2190
2191         if (argc > 0) {
2192                 printername = argv[0];
2193         } else {
2194                 printername = "*";
2195         }
2196
2197         if (argc > 1) {
2198                 servername =  argv[1];
2199         } else {
2200                 servername = lp_netbios_name();
2201         }
2202
2203         rc = ads_find_printer_on_server(ads, &res, printername, servername);
2204
2205         if (!ADS_ERR_OK(rc)) {
2206                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2207                         servername, ads_errstr(rc));
2208                 ads_msgfree(ads, res);
2209                 ads_destroy(&ads);
2210                 return -1;
2211         }
2212
2213         if (ads_count_replies(ads, res) == 0) {
2214                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2215                 ads_msgfree(ads, res);
2216                 ads_destroy(&ads);
2217                 return -1;
2218         }
2219
2220         ads_dump(ads, res);
2221         ads_msgfree(ads, res);
2222         ads_destroy(&ads);
2223
2224         return 0;
2225 }
2226
2227 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2228 {
2229         ADS_STRUCT *ads;
2230         ADS_STATUS rc;
2231         const char *servername, *printername;
2232         struct cli_state *cli = NULL;
2233         struct rpc_pipe_client *pipe_hnd = NULL;
2234         struct sockaddr_storage server_ss;
2235         NTSTATUS nt_status;
2236         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2237         ADS_MODLIST mods = ads_init_mods(mem_ctx);
2238         char *prt_dn, *srv_dn, **srv_cn;
2239         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2240         LDAPMessage *res = NULL;
2241         bool ok;
2242
2243         if (argc < 1 || c->display_usage) {
2244                 d_printf("%s\n%s",
2245                          _("Usage:"),
2246                          _("net ads printer publish <printername> [servername]\n"
2247                            "  Publish printer in AD\n"
2248                            "    printername\tName of the printer\n"
2249                            "    servername\tName of the print server\n"));
2250                 talloc_destroy(mem_ctx);
2251                 return -1;
2252         }
2253
2254         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2255                 talloc_destroy(mem_ctx);
2256                 return -1;
2257         }
2258
2259         printername = argv[0];
2260
2261         if (argc == 2) {
2262                 servername = argv[1];
2263         } else {
2264                 servername = lp_netbios_name();
2265         }
2266
2267         /* Get printer data from SPOOLSS */
2268
2269         ok = resolve_name(servername, &server_ss, 0x20, false);
2270         if (!ok) {
2271                 d_fprintf(stderr, _("Could not find server %s\n"),
2272                           servername);
2273                 ads_destroy(&ads);
2274                 talloc_destroy(mem_ctx);
2275                 return -1;
2276         }
2277
2278         cli_credentials_set_kerberos_state(c->creds,
2279                                            CRED_USE_KERBEROS_REQUIRED,
2280                                            CRED_SPECIFIED);
2281
2282         nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2283                                         &server_ss, 0,
2284                                         "IPC$", "IPC",
2285                                         c->creds,
2286                                         CLI_FULL_CONNECTION_IPC);
2287
2288         if (NT_STATUS_IS_ERR(nt_status)) {
2289                 d_fprintf(stderr, _("Unable to open a connection to %s to "
2290                                     "obtain data for %s\n"),
2291                           servername, printername);
2292                 ads_destroy(&ads);
2293                 talloc_destroy(mem_ctx);
2294                 return -1;
2295         }
2296
2297         /* Publish on AD server */
2298
2299         ads_find_machine_acct(ads, &res, servername);
2300
2301         if (ads_count_replies(ads, res) == 0) {
2302                 d_fprintf(stderr, _("Could not find machine account for server "
2303                                     "%s\n"),
2304                          servername);
2305                 ads_destroy(&ads);
2306                 talloc_destroy(mem_ctx);
2307                 return -1;
2308         }
2309
2310         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2311         srv_cn = ldap_explode_dn(srv_dn, 1);
2312
2313         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2314         printername_escaped = escape_rdn_val_string_alloc(printername);
2315         if (!srv_cn_escaped || !printername_escaped) {
2316                 SAFE_FREE(srv_cn_escaped);
2317                 SAFE_FREE(printername_escaped);
2318                 d_fprintf(stderr, _("Internal error, out of memory!"));
2319                 ads_destroy(&ads);
2320                 talloc_destroy(mem_ctx);
2321                 return -1;
2322         }
2323
2324         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2325                 SAFE_FREE(srv_cn_escaped);
2326                 SAFE_FREE(printername_escaped);
2327                 d_fprintf(stderr, _("Internal error, out of memory!"));
2328                 ads_destroy(&ads);
2329                 talloc_destroy(mem_ctx);
2330                 return -1;
2331         }
2332
2333         SAFE_FREE(srv_cn_escaped);
2334         SAFE_FREE(printername_escaped);
2335
2336         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2337         if (!NT_STATUS_IS_OK(nt_status)) {
2338                 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2339                          servername);
2340                 SAFE_FREE(prt_dn);
2341                 ads_destroy(&ads);
2342                 talloc_destroy(mem_ctx);
2343                 return -1;
2344         }
2345
2346         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2347                                                               printername))) {
2348                 SAFE_FREE(prt_dn);
2349                 ads_destroy(&ads);
2350                 talloc_destroy(mem_ctx);
2351                 return -1;
2352         }
2353
2354         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2355         if (!ADS_ERR_OK(rc)) {
2356                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2357                 SAFE_FREE(prt_dn);
2358                 ads_destroy(&ads);
2359                 talloc_destroy(mem_ctx);
2360                 return -1;
2361         }
2362
2363         d_printf("published printer\n");
2364         SAFE_FREE(prt_dn);
2365         ads_destroy(&ads);
2366         talloc_destroy(mem_ctx);
2367
2368         return 0;
2369 }
2370
2371 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2372 {
2373         ADS_STRUCT *ads;
2374         ADS_STATUS rc;
2375         const char *servername;
2376         char *prt_dn;
2377         LDAPMessage *res = NULL;
2378
2379         if (argc < 1 || c->display_usage) {
2380                 d_printf("%s\n%s",
2381                          _("Usage:"),
2382                          _("net ads printer remove <printername> [servername]\n"
2383                            "  Remove a printer from the AD\n"
2384                            "    printername\tName of the printer\n"
2385                            "    servername\tName of the print server\n"));
2386                 return -1;
2387         }
2388
2389         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2390                 return -1;
2391         }
2392
2393         if (argc > 1) {
2394                 servername = argv[1];
2395         } else {
2396                 servername = lp_netbios_name();
2397         }
2398
2399         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2400
2401         if (!ADS_ERR_OK(rc)) {
2402                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2403                 ads_msgfree(ads, res);
2404                 ads_destroy(&ads);
2405                 return -1;
2406         }
2407
2408         if (ads_count_replies(ads, res) == 0) {
2409                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2410                 ads_msgfree(ads, res);
2411                 ads_destroy(&ads);
2412                 return -1;
2413         }
2414
2415         prt_dn = ads_get_dn(ads, talloc_tos(), res);
2416         ads_msgfree(ads, res);
2417         rc = ads_del_dn(ads, prt_dn);
2418         TALLOC_FREE(prt_dn);
2419
2420         if (!ADS_ERR_OK(rc)) {
2421                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2422                 ads_destroy(&ads);
2423                 return -1;
2424         }
2425
2426         ads_destroy(&ads);
2427         return 0;
2428 }
2429
2430 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2431 {
2432         struct functable func[] = {
2433                 {
2434                         "search",
2435                         net_ads_printer_search,
2436                         NET_TRANSPORT_ADS,
2437                         N_("Search for a printer"),
2438                         N_("net ads printer search\n"
2439                            "    Search for a printer")
2440                 },
2441                 {
2442                         "info",
2443                         net_ads_printer_info,
2444                         NET_TRANSPORT_ADS,
2445                         N_("Display printer information"),
2446                         N_("net ads printer info\n"
2447                            "    Display printer information")
2448                 },
2449                 {
2450                         "publish",
2451                         net_ads_printer_publish,
2452                         NET_TRANSPORT_ADS,
2453                         N_("Publish a printer"),
2454                         N_("net ads printer publish\n"
2455                            "    Publish a printer")
2456                 },
2457                 {
2458                         "remove",
2459                         net_ads_printer_remove,
2460                         NET_TRANSPORT_ADS,
2461                         N_("Delete a printer"),
2462                         N_("net ads printer remove\n"
2463                            "    Delete a printer")
2464                 },
2465                 {NULL, NULL, 0, NULL, NULL}
2466         };
2467
2468         return net_run_function(c, argc, argv, "net ads printer", func);
2469 }
2470
2471
2472 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2473 {
2474         ADS_STRUCT *ads;
2475         const char *auth_principal = cli_credentials_get_username(c->creds);
2476         const char *auth_password = cli_credentials_get_password(c->creds);
2477         const char *realm = NULL;
2478         const char *new_password = NULL;
2479         char *chr, *prompt;
2480         const char *user;
2481         char pwd[256] = {0};
2482         ADS_STATUS ret;
2483
2484         if (c->display_usage) {
2485                 d_printf("%s\n%s",
2486                          _("Usage:"),
2487                          _("net ads password <username>\n"
2488                            "  Change password for user\n"
2489                            "    username\tName of user to change password for\n"));
2490                 return 0;
2491         }
2492
2493         if (auth_principal == NULL || auth_password == NULL) {
2494                 d_fprintf(stderr, _("You must supply an administrator "
2495                                     "username/password\n"));
2496                 return -1;
2497         }
2498
2499         if (argc < 1) {
2500                 d_fprintf(stderr, _("ERROR: You must say which username to "
2501                                     "change password for\n"));
2502                 return -1;
2503         }
2504
2505         user = argv[0];
2506         if (!strchr_m(user, '@')) {
2507                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2508                         return -1;
2509                 }
2510                 user = chr;
2511         }
2512
2513         use_in_memory_ccache();
2514         chr = strchr_m(auth_principal, '@');
2515         if (chr) {
2516                 realm = ++chr;
2517         } else {
2518                 realm = lp_realm();
2519         }
2520
2521         /* use the realm so we can eventually change passwords for users
2522         in realms other than default */
2523         ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2524         if (ads == NULL) {
2525                 return -1;
2526         }
2527
2528         /* we don't actually need a full connect, but it's the easy way to
2529                 fill in the KDC's addresss */
2530         ads_connect(ads);
2531
2532         if (!ads->config.realm) {
2533                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2534                 ads_destroy(&ads);
2535                 return -1;
2536         }
2537
2538         if (argv[1]) {
2539                 new_password = (const char *)argv[1];
2540         } else {
2541                 int rc;
2542
2543                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2544                         return -1;
2545                 }
2546                 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2547                 if (rc < 0) {
2548                         return -1;
2549                 }
2550                 new_password = pwd;
2551                 free(prompt);
2552         }
2553
2554         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2555                                 auth_password, user, new_password, ads->auth.time_offset);
2556         memset(pwd, '\0', sizeof(pwd));
2557         if (!ADS_ERR_OK(ret)) {
2558                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2559                 ads_destroy(&ads);
2560                 return -1;
2561         }
2562
2563         d_printf(_("Password change for %s completed.\n"), user);
2564         ads_destroy(&ads);
2565
2566         return 0;
2567 }
2568
2569 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2570 {
2571         ADS_STRUCT *ads;
2572         char *host_principal;
2573         fstring my_name;
2574         ADS_STATUS ret;
2575
2576         if (c->display_usage) {
2577                 d_printf(  "%s\n"
2578                            "net ads changetrustpw\n"
2579                            "    %s\n",
2580                          _("Usage:"),
2581                          _("Change the machine account's trust password"));
2582                 return 0;
2583         }
2584
2585         if (!secrets_init()) {
2586                 DEBUG(1,("Failed to initialise secrets database\n"));
2587                 return -1;
2588         }
2589
2590         net_use_krb_machine_account(c);
2591
2592         use_in_memory_ccache();
2593
2594         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2595                 return -1;
2596         }
2597
2598         fstrcpy(my_name, lp_netbios_name());
2599         if (!strlower_m(my_name)) {
2600                 ads_destroy(&ads);
2601                 return -1;
2602         }
2603
2604         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2605                 ads_destroy(&ads);
2606                 return -1;
2607         }
2608         d_printf(_("Changing password for principal: %s\n"), host_principal);
2609
2610         ret = ads_change_trust_account_password(ads, host_principal);
2611
2612         if (!ADS_ERR_OK(ret)) {
2613                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2614                 ads_destroy(&ads);
2615                 SAFE_FREE(host_principal);
2616                 return -1;
2617         }
2618
2619         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2620
2621         if (USE_SYSTEM_KEYTAB) {
2622                 d_printf(_("Attempting to update system keytab with new password.\n"));
2623                 if (ads_keytab_create_default(ads)) {
2624                         d_printf(_("Failed to update system keytab.\n"));
2625                 }
2626         }
2627
2628         ads_destroy(&ads);
2629         SAFE_FREE(host_principal);
2630
2631         return 0;
2632 }
2633
2634 /*
2635   help for net ads search
2636 */
2637 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2638 {
2639         d_printf(_(
2640                 "\nnet ads search <expression> <attributes...>\n"
2641                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2642                 "The expression is a standard LDAP search expression, and the\n"
2643                 "attributes are a list of LDAP fields to show in the results.\n\n"
2644                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2645                 ));
2646         net_common_flags_usage(c, argc, argv);
2647         return -1;
2648 }
2649
2650
2651 /*
2652   general ADS search function. Useful in diagnosing problems in ADS
2653 */
2654 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2655 {
2656         ADS_STRUCT *ads;
2657         ADS_STATUS rc;
2658         const char *ldap_exp;
2659         const char **attrs;
2660         LDAPMessage *res = NULL;
2661
2662         if (argc < 1 || c->display_usage) {
2663                 return net_ads_search_usage(c, argc, argv);
2664         }
2665
2666         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2667                 return -1;
2668         }
2669
2670         ldap_exp = argv[0];
2671         attrs = (argv + 1);
2672
2673         rc = ads_do_search_retry(ads, ads->config.bind_path,
2674                                LDAP_SCOPE_SUBTREE,
2675                                ldap_exp, attrs, &res);
2676         if (!ADS_ERR_OK(rc)) {
2677                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2678                 ads_destroy(&ads);
2679                 return -1;
2680         }
2681
2682         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2683
2684         /* dump the results */
2685         ads_dump(ads, res);
2686
2687         ads_msgfree(ads, res);
2688         ads_destroy(&ads);
2689
2690         return 0;
2691 }
2692
2693
2694 /*
2695   help for net ads search
2696 */
2697 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2698 {
2699         d_printf(_(
2700                 "\nnet ads dn <dn> <attributes...>\n"
2701                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2702                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2703                 "to show in the results\n\n"
2704                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2705                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2706                 ));
2707         net_common_flags_usage(c, argc, argv);
2708         return -1;
2709 }
2710
2711
2712 /*
2713   general ADS search function. Useful in diagnosing problems in ADS
2714 */
2715 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2716 {
2717         ADS_STRUCT *ads;
2718         ADS_STATUS rc;
2719         const char *dn;
2720         const char **attrs;
2721         LDAPMessage *res = NULL;
2722
2723         if (argc < 1 || c->display_usage) {
2724                 return net_ads_dn_usage(c, argc, argv);
2725         }
2726
2727         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2728                 return -1;
2729         }
2730
2731         dn = argv[0];
2732         attrs = (argv + 1);
2733
2734         rc = ads_do_search_all(ads, dn,
2735                                LDAP_SCOPE_BASE,
2736                                "(objectclass=*)", attrs, &res);
2737         if (!ADS_ERR_OK(rc)) {
2738                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2739                 ads_destroy(&ads);
2740                 return -1;
2741         }
2742
2743         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2744
2745         /* dump the results */
2746         ads_dump(ads, res);
2747
2748         ads_msgfree(ads, res);
2749         ads_destroy(&ads);
2750
2751         return 0;
2752 }
2753
2754 /*
2755   help for net ads sid search
2756 */
2757 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2758 {
2759         d_printf(_(
2760                 "\nnet ads sid <sid> <attributes...>\n"
2761                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2762                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2763                 "to show in the results\n\n"
2764                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2765                 ));
2766         net_common_flags_usage(c, argc, argv);
2767         return -1;
2768 }
2769
2770
2771 /*
2772   general ADS search function. Useful in diagnosing problems in ADS
2773 */
2774 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2775 {
2776         ADS_STRUCT *ads;
2777         ADS_STATUS rc;
2778         const char *sid_string;
2779         const char **attrs;
2780         LDAPMessage *res = NULL;
2781         struct dom_sid sid;
2782
2783         if (argc < 1 || c->display_usage) {
2784                 return net_ads_sid_usage(c, argc, argv);
2785         }
2786
2787         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2788                 return -1;
2789         }
2790
2791         sid_string = argv[0];
2792         attrs = (argv + 1);
2793
2794         if (!string_to_sid(&sid, sid_string)) {
2795                 d_fprintf(stderr, _("could not convert sid\n"));
2796                 ads_destroy(&ads);
2797                 return -1;
2798         }
2799
2800         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2801         if (!ADS_ERR_OK(rc)) {
2802                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2803                 ads_destroy(&ads);
2804                 return -1;
2805         }
2806
2807         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2808
2809         /* dump the results */
2810         ads_dump(ads, res);
2811
2812         ads_msgfree(ads, res);
2813         ads_destroy(&ads);
2814
2815         return 0;
2816 }
2817
2818 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2819 {
2820         int ret;
2821         ADS_STRUCT *ads;
2822
2823         if (c->display_usage) {
2824                 d_printf(  "%s\n"
2825                            "net ads keytab flush\n"
2826                            "    %s\n",
2827                          _("Usage:"),
2828                          _("Delete the whole keytab"));
2829                 return 0;
2830         }
2831
2832         if (!c->opt_user_specified && c->opt_password == NULL) {
2833                 net_use_krb_machine_account(c);
2834         }
2835
2836         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2837                 return -1;
2838         }
2839         ret = ads_keytab_flush(ads);
2840         ads_destroy(&ads);
2841         return ret;
2842 }
2843
2844 static int net_ads_keytab_add(struct net_context *c,
2845                               int argc,
2846                               const char **argv,
2847                               bool update_ads)
2848 {
2849         int i;
2850         int ret = 0;
2851         ADS_STRUCT *ads;
2852
2853         if (c->display_usage) {
2854                 d_printf("%s\n%s",
2855                          _("Usage:"),
2856                          _("net ads keytab add <principal> [principal ...]\n"
2857                            "  Add principals to local keytab\n"
2858                            "    principal\tKerberos principal to add to "
2859                            "keytab\n"));
2860                 return 0;
2861         }
2862
2863         d_printf(_("Processing principals to add...\n"));
2864
2865         if (!c->opt_user_specified && c->opt_password == NULL) {
2866                 net_use_krb_machine_account(c);
2867         }
2868
2869         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2870                 return -1;
2871         }
2872         for (i = 0; i < argc; i++) {
2873                 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2874         }
2875         ads_destroy(&ads);
2876         return ret;
2877 }
2878
2879 static int net_ads_keytab_add_default(struct net_context *c,
2880                                       int argc,
2881                                       const char **argv)
2882 {
2883         return net_ads_keytab_add(c, argc, argv, false);
2884 }
2885
2886 static int net_ads_keytab_add_update_ads(struct net_context *c,
2887                                          int argc,
2888                                          const char **argv)
2889 {
2890         return net_ads_keytab_add(c, argc, argv, true);
2891 }
2892
2893 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2894 {
2895         ADS_STRUCT *ads;
2896         int ret;
2897
2898         if (c->display_usage) {
2899                 d_printf(  "%s\n"
2900                            "net ads keytab create\n"
2901                            "    %s\n",
2902                          _("Usage:"),
2903                          _("Create new default keytab"));
2904                 return 0;
2905         }
2906
2907         if (!c->opt_user_specified && c->opt_password == NULL) {
2908                 net_use_krb_machine_account(c);
2909         }
2910
2911         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2912                 return -1;
2913         }
2914         ret = ads_keytab_create_default(ads);
2915         ads_destroy(&ads);
2916         return ret;
2917 }
2918
2919 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2920 {
2921         const char *keytab = NULL;
2922
2923         if (c->display_usage) {
2924                 d_printf("%s\n%s",
2925                          _("Usage:"),
2926                          _("net ads keytab list [keytab]\n"
2927                            "  List a local keytab\n"
2928                            "    keytab\tKeytab to list\n"));
2929                 return 0;
2930         }
2931
2932         if (argc >= 1) {
2933                 keytab = argv[0];
2934         }
2935
2936         return ads_keytab_list(keytab);
2937 }
2938
2939
2940 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2941 {
2942         struct functable func[] = {
2943                 {
2944                         "add",
2945                         net_ads_keytab_add_default,
2946                         NET_TRANSPORT_ADS,
2947                         N_("Add a service principal"),
2948                         N_("net ads keytab add\n"
2949                            "    Add a service principal, updates keytab file only.")
2950                 },
2951                 {
2952                         "add_update_ads",
2953                         net_ads_keytab_add_update_ads,
2954                         NET_TRANSPORT_ADS,
2955                         N_("Add a service principal"),
2956                         N_("net ads keytab add_update_ads\n"
2957                            "    Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2958                 },
2959                 {
2960                         "create",
2961                         net_ads_keytab_create,
2962                         NET_TRANSPORT_ADS,
2963                         N_("Create a fresh keytab"),
2964                         N_("net ads keytab create\n"
2965                            "    Create a fresh keytab or update existing one.")
2966                 },
2967                 {
2968                         "flush",
2969                         net_ads_keytab_flush,
2970                         NET_TRANSPORT_ADS,
2971                         N_("Remove all keytab entries"),
2972                         N_("net ads keytab flush\n"
2973                            "    Remove all keytab entries")
2974                 },
2975                 {
2976                         "list",
2977                         net_ads_keytab_list,
2978                         NET_TRANSPORT_ADS,
2979                         N_("List a keytab"),
2980                         N_("net ads keytab list\n"
2981                            "    List a keytab")
2982                 },
2983                 {NULL, NULL, 0, NULL, NULL}
2984         };
2985
2986         if (!USE_KERBEROS_KEYTAB) {
2987                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2988                     "keytab method to use keytab functions.\n"));
2989         }
2990
2991         return net_run_function(c, argc, argv, "net ads keytab", func);
2992 }
2993
2994 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2995 {
2996         int ret = -1;
2997
2998         if (c->display_usage) {
2999                 d_printf(  "%s\n"
3000                            "net ads kerberos renew\n"
3001                            "    %s\n",
3002                          _("Usage:"),
3003                          _("Renew TGT from existing credential cache"));
3004                 return 0;
3005         }
3006
3007         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3008         if (ret) {
3009                 d_printf(_("failed to renew kerberos ticket: %s\n"),
3010                         error_message(ret));
3011         }
3012         return ret;
3013 }
3014
3015 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3016                                        struct PAC_DATA_CTR **pac_data_ctr)
3017 {
3018         NTSTATUS status;
3019         int ret = -1;
3020         const char *impersonate_princ_s = NULL;
3021         const char *local_service = NULL;
3022         int i;
3023
3024         for (i=0; i<argc; i++) {
3025                 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3026                         impersonate_princ_s = get_string_param(argv[i]);
3027                         if (impersonate_princ_s == NULL) {
3028                                 return -1;
3029                         }
3030                 }
3031                 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3032                         local_service = get_string_param(argv[i]);
3033                         if (local_service == NULL) {
3034                                 return -1;
3035                         }
3036                 }
3037         }
3038
3039         if (local_service == NULL) {
3040                 local_service = talloc_asprintf(c, "%s$@%s",
3041                                                 lp_netbios_name(), lp_realm());
3042                 if (local_service == NULL) {
3043                         goto out;
3044                 }
3045         }
3046
3047         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3048
3049         status = kerberos_return_pac(c,
3050                                      c->opt_user_name,
3051                                      c->opt_password,
3052                                      0,
3053                                      NULL,
3054                                      NULL,
3055                                      NULL,
3056                                      true,
3057                                      true,
3058                                      2592000, /* one month */
3059                                      impersonate_princ_s,
3060                                      local_service,
3061                                      NULL,
3062                                      NULL,
3063                                      pac_data_ctr);
3064         if (!NT_STATUS_IS_OK(status)) {
3065                 d_printf(_("failed to query kerberos PAC: %s\n"),
3066                         nt_errstr(status));
3067                 goto out;
3068         }
3069
3070         ret = 0;
3071  out:
3072         return ret;
3073 }
3074
3075 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3076 {
3077         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3078         int i, num_buffers;
3079         int ret = -1;
3080         enum PAC_TYPE type = 0;
3081
3082         if (c->display_usage) {
3083                 d_printf(  "%s\n"
3084                            "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3085                            "    %s\n",
3086                          _("Usage:"),
3087                          _("Dump the Kerberos PAC"));
3088                 return -1;
3089         }
3090
3091         for (i=0; i<argc; i++) {
3092                 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3093                         type = get_int_param(argv[i]);
3094                 }
3095         }
3096
3097         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3098         if (ret) {
3099                 return ret;
3100         }
3101
3102         if (type == 0) {
3103
3104                 char *s = NULL;
3105
3106                 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3107                         pac_data_ctr->pac_data);
3108                 if (s != NULL) {
3109                         d_printf(_("The Pac: %s\n"), s);
3110                         talloc_free(s);
3111                 }
3112
3113                 return 0;
3114         }
3115
3116         num_buffers = pac_data_ctr->pac_data->num_buffers;
3117
3118         for (i=0; i<num_buffers; i++) {
3119
3120                 char *s = NULL;
3121
3122                 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3123                         continue;
3124                 }
3125
3126                 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3127                                 pac_data_ctr->pac_data->buffers[i].info);
3128                 if (s != NULL) {
3129                         d_printf(_("The Pac: %s\n"), s);
3130                         talloc_free(s);
3131                 }
3132                 break;
3133         }
3134
3135         return 0;
3136 }
3137
3138 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3139 {
3140         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3141         char *filename = NULL;
3142         int ret = -1;
3143         int i;
3144
3145         if (c->display_usage) {
3146                 d_printf(  "%s\n"
3147                            "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3148                            "    %s\n",
3149                          _("Usage:"),
3150                          _("Save the Kerberos PAC"));
3151                 return -1;
3152         }
3153
3154         for (i=0; i<argc; i++) {
3155                 if (strnequal(argv[i], "filename", strlen("filename"))) {
3156                         filename = get_string_param(argv[i]);
3157                         if (filename == NULL) {
3158                                 return -1;
3159                         }
3160                 }
3161         }
3162
3163         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3164         if (ret) {
3165                 return ret;
3166         }
3167
3168         if (filename == NULL) {
3169                 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3170                 return -1;
3171         }
3172
3173         /* save the raw format */
3174         if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3175                 d_printf(_("failed to save PAC in %s\n"), filename);
3176                 return -1;
3177         }
3178
3179         return 0;
3180 }
3181
3182 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3183 {
3184         struct functable func[] = {
3185                 {
3186                         "dump",
3187                         net_ads_kerberos_pac_dump,
3188                         NET_TRANSPORT_ADS,
3189                         N_("Dump Kerberos PAC"),
3190                         N_("net ads kerberos pac dump\n"
3191                            "    Dump a Kerberos PAC to stdout")
3192                 },
3193                 {
3194                         "save",
3195                         net_ads_kerberos_pac_save,
3196                         NET_TRANSPORT_ADS,
3197                         N_("Save Kerberos PAC"),
3198                         N_("net ads kerberos pac save\n"
3199                            "    Save a Kerberos PAC in a file")
3200                 },
3201
3202                 {NULL, NULL, 0, NULL, NULL}
3203         };
3204
3205         return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3206 }
3207
3208 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3209 {
3210         TALLOC_CTX *mem_ctx = NULL;
3211         int ret = -1;
3212         NTSTATUS status;
3213
3214         if (c->display_usage) {
3215                 d_printf(  "%s\n"
3216                            "net ads kerberos kinit\n"
3217                            "    %s\n",
3218                          _("Usage:"),
3219                          _("Get Ticket Granting Ticket (TGT) for the user"));
3220                 return 0;
3221         }
3222
3223         mem_ctx = talloc_init("net_ads_kerberos_kinit");
3224         if (!mem_ctx) {
3225                 goto out;
3226         }
3227
3228         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3229
3230         ret = kerberos_kinit_password_ext(c->opt_user_name,
3231                                           c->opt_password,
3232                                           0,
3233                                           NULL,
3234                                           NULL,
3235                                           NULL,
3236                                           true,
3237                                           true,
3238                                           2592000, /* one month */
3239                                           NULL,
3240                                           NULL,
3241                                           NULL,
3242                                           &status);
3243         if (ret) {
3244                 d_printf(_("failed to kinit password: %s\n"),
3245                         nt_errstr(status));
3246         }
3247  out:
3248         return ret;
3249 }
3250
3251 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3252 {
3253         struct functable func[] = {
3254                 {
3255                         "kinit",
3256                         net_ads_kerberos_kinit,
3257                         NET_TRANSPORT_ADS,
3258                         N_("Retrieve Ticket Granting Ticket (TGT)"),
3259                         N_("net ads kerberos kinit\n"
3260                            "    Receive Ticket Granting Ticket (TGT)")
3261                 },
3262                 {
3263                         "renew",
3264                         net_ads_kerberos_renew,
3265                         NET_TRANSPORT_ADS,
3266                         N_("Renew Ticket Granting Ticket from credential cache"),
3267                         N_("net ads kerberos renew\n"
3268                            "    Renew Ticket Granting Ticket (TGT) from "
3269                            "credential cache")
3270                 },
3271                 {
3272                         "pac",
3273                         net_ads_kerberos_pac,
3274                         NET_TRANSPORT_ADS,
3275                         N_("Dump Kerberos PAC"),
3276                         N_("net ads kerberos pac\n"
3277                            "    Dump Kerberos PAC")
3278                 },
3279                 {NULL, NULL, 0, NULL, NULL}
3280         };
3281
3282         return net_run_function(c, argc, argv, "net ads kerberos", func);
3283 }
3284
3285 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3286 {
3287         int ret = 0;
3288         bool ok = false;
3289         ADS_STRUCT *ads = NULL;
3290         if (c->display_usage) {
3291                 d_printf("%s\n%s",
3292                          _("Usage:"),
3293                          _("net ads setspn list <machinename>\n"));
3294                 ret = 0;
3295                 goto done;
3296         }
3297         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3298                 ret = -1;
3299                 goto done;
3300         }
3301         if (argc) {
3302                 ok = ads_setspn_list(ads, argv[0]);
3303         } else {
3304                 ok = ads_setspn_list(ads, lp_netbios_name());
3305         }
3306         if (!ok) {
3307             ret = -1;
3308         }
3309 done:
3310         if (ads) {
3311                 ads_destroy(&ads);
3312         }
3313         return ret;
3314 }
3315
3316 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3317 {
3318         int ret = 0;
3319         bool ok = false;
3320         ADS_STRUCT *ads = NULL;
3321         if (c->display_usage || argc < 1) {
3322                 d_printf("%s\n%s",
3323                          _("Usage:"),
3324                          _("net ads setspn add <machinename> SPN\n"));
3325                 ret = 0;
3326                 goto done;
3327         }
3328         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3329                 ret = -1;
3330                 goto done;
3331         }
3332         if (argc > 1) {
3333                 ok = ads_setspn_add(ads, argv[0], argv[1]);
3334         } else {
3335                 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3336         }
3337         if (!ok) {
3338             ret = -1;
3339         }
3340 done:
3341         if (ads) {
3342                 ads_destroy(&ads);
3343         }
3344         return ret;
3345 }
3346
3347 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3348 {
3349         int ret = 0;
3350         bool ok = false;
3351         ADS_STRUCT *ads = NULL;
3352         if (c->display_usage || argc < 1) {
3353                 d_printf("%s\n%s",
3354                          _("Usage:"),
3355                          _("net ads setspn delete <machinename> SPN\n"));
3356                 ret = 0;
3357                 goto done;
3358         }
3359         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3360                 ret = -1;
3361                 goto done;
3362         }
3363         if (argc > 1) {
3364                 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3365         } else {
3366                 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3367         }
3368         if (!ok) {
3369                 ret = -1;
3370         }
3371 done:
3372         if (ads) {
3373                 ads_destroy(&ads);
3374         }
3375         return ret;
3376 }
3377
3378 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3379 {
3380         struct functable func[] = {
3381                 {
3382                         "list",
3383                         net_ads_setspn_list,
3384                         NET_TRANSPORT_ADS,
3385                         N_("List Service Principal Names (SPN)"),
3386                         N_("net ads setspn list machine\n"
3387                            "    List Service Principal Names (SPN)")
3388                 },
3389                 {
3390                         "add",
3391                         net_ads_setspn_add,
3392                         NET_TRANSPORT_ADS,
3393                         N_("Add Service Principal Names (SPN)"),
3394                         N_("net ads setspn add machine spn\n"
3395                            "    Add Service Principal Names (SPN)")
3396                 },
3397                 {
3398                         "delete",
3399                         net_ads_setspn_delete,
3400                         NET_TRANSPORT_ADS,
3401                         N_("Delete Service Principal Names (SPN)"),
3402                         N_("net ads setspn delete machine spn\n"
3403                            "    Delete Service Principal Names (SPN)")
3404                 },
3405                 {NULL, NULL, 0, NULL, NULL}
3406         };
3407
3408         return net_run_function(c, argc, argv, "net ads setspn", func);
3409 }
3410
3411 static int net_ads_enctype_lookup_account(struct net_context *c,
3412                                           ADS_STRUCT *ads,
3413                                           const char *account,
3414                                           LDAPMessage **res,
3415                                           const char **enctype_str)
3416 {
3417         const char *filter;
3418         const char *attrs[] = {
3419                 "msDS-SupportedEncryptionTypes",
3420                 NULL
3421         };
3422         int count;
3423         int ret = -1;
3424         ADS_STATUS status;
3425
3426         filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3427                                  account);
3428         if (filter == NULL) {
3429                 goto done;
3430         }
3431
3432         status = ads_search(ads, res, filter, attrs);
3433         if (!ADS_ERR_OK(status)) {
3434                 d_printf(_("no account found with filter: %s\n"), filter);
3435                 goto done;
3436         }
3437
3438         count = ads_count_replies(ads, *res);
3439         switch (count) {
3440         case 1:
3441                 break;
3442         case 0:
3443                 d_printf(_("no account found with filter: %s\n"), filter);
3444                 goto done;
3445         default:
3446                 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3447                 goto done;
3448         }
3449
3450         if (enctype_str) {
3451                 *enctype_str = ads_pull_string(ads, c, *res,
3452                                                "msDS-SupportedEncryptionTypes");
3453                 if (*enctype_str == NULL) {
3454                         d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3455                         goto done;
3456                 }
3457         }
3458
3459         ret = 0;
3460  done:
3461         return ret;
3462 }
3463
3464 static void net_ads_enctype_dump_enctypes(const char *username,
3465                                           const char *enctype_str)
3466 {
3467         int enctypes = atoi(enctype_str);
3468
3469         d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3470                 username, enctypes, enctypes);
3471
3472         printf("[%s] 0x%08x DES-CBC-CRC\n",
3473                 enctypes & ENC_CRC32 ? "X" : " ",
3474                 ENC_CRC32);
3475         printf("[%s] 0x%08x DES-CBC-MD5\n",
3476                 enctypes & ENC_RSA_MD5 ? "X" : " ",
3477                 ENC_RSA_MD5);
3478         printf("[%s] 0x%08x RC4-HMAC\n",
3479                 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3480                 ENC_RC4_HMAC_MD5);
3481         printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3482                 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3483                 ENC_HMAC_SHA1_96_AES128);
3484         printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3485                 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3486                 ENC_HMAC_SHA1_96_AES256);
3487 }
3488
3489 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3490 {
3491         int ret = -1;
3492         ADS_STATUS status;
3493         ADS_STRUCT *ads = NULL;
3494         LDAPMessage *res = NULL;
3495         const char *str = NULL;
3496
3497         if (c->display_usage || (argc < 1)) {
3498                 d_printf(  "%s\n"
3499                            "net ads enctypes list\n"
3500                            "    %s\n",
3501                          _("Usage:"),
3502                          _("List supported enctypes"));
3503                 return 0;
3504         }
3505
3506         status = ads_startup(c, false, &ads);
3507         if (!ADS_ERR_OK(status)) {
3508                 printf("startup failed\n");
3509                 return ret;
3510         }
3511
3512         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3513         if (ret) {
3514                 goto done;
3515         }
3516
3517         net_ads_enctype_dump_enctypes(argv[0], str);
3518
3519         ret = 0;
3520  done:
3521         ads_msgfree(ads, res);
3522         ads_destroy(&ads);
3523
3524         return ret;
3525 }
3526
3527 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3528 {
3529         int ret = -1;
3530         ADS_STATUS status;
3531         ADS_STRUCT *ads;
3532         LDAPMessage *res = NULL;
3533         const char *etype_list_str;
3534         const char *dn;
3535         ADS_MODLIST mods;
3536         uint32_t etype_list;
3537         const char *str;
3538
3539         if (c->display_usage || argc < 1) {
3540                 d_printf(  "%s\n"
3541                            "net ads enctypes set <sAMAccountName> [enctypes]\n"
3542                            "    %s\n",
3543                          _("Usage:"),
3544                          _("Set supported enctypes"));
3545                 return 0;
3546         }
3547
3548         status = ads_startup(c, false, &ads);
3549         if (!ADS_ERR_OK(status)) {
3550                 printf("startup failed\n");
3551                 return ret;
3552         }
3553
3554         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3555         if (ret) {
3556                 goto done;
3557         }
3558
3559         dn = ads_get_dn(ads, c, res);
3560         if (dn == NULL) {
3561                 goto done;
3562         }
3563
3564         etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3565 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3566         etype_list |= ENC_HMAC_SHA1_96_AES128;
3567 #endif
3568 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3569         etype_list |= ENC_HMAC_SHA1_96_AES256;
3570 #endif
3571
3572         if (argv[1] != NULL) {
3573                 sscanf(argv[1], "%i", &etype_list);
3574         }
3575
3576         etype_list_str = talloc_asprintf(c, "%d", etype_list);
3577         if (!etype_list_str) {
3578                 goto done;
3579         }
3580
3581         mods = ads_init_mods(c);
3582         if (!mods) {
3583                 goto done;
3584         }
3585
3586         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3587                              etype_list_str);
3588         if (!ADS_ERR_OK(status)) {
3589                 goto done;
3590         }
3591
3592         status = ads_gen_mod(ads, dn, mods);
3593         if (!ADS_ERR_OK(status)) {
3594                 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3595                         ads_errstr(status));
3596                 goto done;
3597         }
3598
3599         ads_msgfree(ads, res);
3600
3601         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3602         if (ret) {
3603                 goto done;
3604         }
3605
3606         net_ads_enctype_dump_enctypes(argv[0], str);
3607
3608         ret = 0;
3609  done:
3610         ads_msgfree(ads, res);
3611         ads_destroy(&ads);
3612
3613         return ret;
3614 }
3615
3616 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3617 {
3618         int ret = -1;
3619         ADS_STATUS status;
3620         ADS_STRUCT *ads;
3621         LDAPMessage *res = NULL;
3622         const char *dn;
3623         ADS_MODLIST mods;
3624
3625         if (c->display_usage || argc < 1) {
3626                 d_printf(  "%s\n"
3627                            "net ads enctypes delete <sAMAccountName>\n"
3628                            "    %s\n",
3629                          _("Usage:"),
3630                          _("Delete supported enctypes"));
3631                 return 0;
3632         }
3633
3634         status = ads_startup(c, false, &ads);
3635         if (!ADS_ERR_OK(status)) {
3636                 printf("startup failed\n");
3637                 return ret;
3638         }
3639
3640         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3641         if (ret) {
3642                 goto done;
3643         }
3644
3645         dn = ads_get_dn(ads, c, res);
3646         if (dn == NULL) {
3647                 goto done;
3648         }
3649
3650         mods = ads_init_mods(c);
3651         if (!mods) {
3652                 goto done;
3653         }
3654
3655         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3656         if (!ADS_ERR_OK(status)) {
3657                 goto done;
3658         }
3659
3660         status = ads_gen_mod(ads, dn, mods);
3661         if (!ADS_ERR_OK(status)) {
3662                 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3663                         ads_errstr(status));
3664                 goto done;
3665         }
3666
3667         ret = 0;
3668
3669  done:
3670         ads_msgfree(ads, res);
3671         ads_destroy(&ads);
3672         return ret;
3673 }
3674
3675 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3676 {
3677         struct functable func[] = {
3678                 {
3679                         "list",
3680                         net_ads_enctypes_list,
3681                         NET_TRANSPORT_ADS,
3682                         N_("List the supported encryption types"),
3683                         N_("net ads enctypes list\n"
3684                            "    List the supported encryption types")
3685                 },
3686                 {
3687                         "set",
3688                         net_ads_enctypes_set,
3689                         NET_TRANSPORT_ADS,
3690                         N_("Set the supported encryption types"),
3691                         N_("net ads enctypes set\n"
3692                            "    Set the supported encryption types")
3693                 },
3694                 {
3695                         "delete",
3696                         net_ads_enctypes_delete,
3697                         NET_TRANSPORT_ADS,
3698                         N_("Delete the supported encryption types"),
3699                         N_("net ads enctypes delete\n"
3700                            "    Delete the supported encryption types")
3701                 },
3702
3703                 {NULL, NULL, 0, NULL, NULL}
3704         };
3705
3706         return net_run_function(c, argc, argv, "net ads enctypes", func);
3707 }
3708
3709
3710 int net_ads(struct net_context *c, int argc, const char **argv)
3711 {
3712         struct functable func[] = {
3713                 {
3714                         "info",
3715                         net_ads_info,
3716                         NET_TRANSPORT_ADS,
3717                         N_("Display details on remote ADS server"),
3718                         N_("net ads info\n"
3719                            "    Display details on remote ADS server")
3720                 },
3721                 {
3722                         "join",
3723                         net_ads_join,
3724                         NET_TRANSPORT_ADS,
3725                         N_("Join the local machine to ADS realm"),
3726                         N_("net ads join\n"
3727                            "    Join the local machine to ADS realm")
3728                 },
3729                 {
3730                         "testjoin",
3731                         net_ads_testjoin,
3732                         NET_TRANSPORT_ADS,
3733                         N_("Validate machine account"),
3734                         N_("net ads testjoin\n"
3735                            "    Validate machine account")
3736                 },
3737                 {
3738                         "leave",
3739                         net_ads_leave,
3740                         NET_TRANSPORT_ADS,
3741                         N_("Remove the local machine from ADS"),
3742                         N_("net ads leave\n"
3743                            "    Remove the local machine from ADS")
3744                 },
3745                 {
3746                         "status",
3747                         net_ads_status,
3748                         NET_TRANSPORT_ADS,
3749                         N_("Display machine account details"),
3750                         N_("net ads status\n"
3751                            "    Display machine account details")
3752                 },
3753                 {
3754                         "user",
3755                         net_ads_user,
3756                         NET_TRANSPORT_ADS,
3757                         N_("List/modify users"),
3758                         N_("net ads user\n"
3759                            "    List/modify users")
3760                 },
3761                 {
3762                         "group",
3763                         net_ads_group,
3764                         NET_TRANSPORT_ADS,
3765                         N_("List/modify groups"),
3766                         N_("net ads group\n"
3767                            "    List/modify groups")
3768                 },
3769                 {
3770                         "dns",
3771                         net_ads_dns,
3772                         NET_TRANSPORT_ADS,
3773                         N_("Issue dynamic DNS update"),
3774                         N_("net ads dns\n"
3775                            "    Issue dynamic DNS update")
3776                 },
3777                 {
3778                         "password",
3779                         net_ads_password,
3780                         NET_TRANSPORT_ADS,
3781                         N_("Change user passwords"),
3782                         N_("net ads password\n"
3783                            "    Change user passwords")
3784                 },
3785                 {
3786                         "changetrustpw",
3787                         net_ads_changetrustpw,
3788                         NET_TRANSPORT_ADS,
3789                         N_("Change trust account password"),
3790                         N_("net ads changetrustpw\n"
3791                            "    Change trust account password")
3792                 },
3793                 {
3794                         "printer",
3795                         net_ads_printer,
3796                         NET_TRANSPORT_ADS,
3797                         N_("List/modify printer entries"),
3798                         N_("net ads printer\n"
3799                            "    List/modify printer entries")
3800                 },
3801                 {
3802                         "search",
3803                         net_ads_search,
3804                         NET_TRANSPORT_ADS,
3805                         N_("Issue LDAP search using filter"),
3806                         N_("net ads search\n"
3807                            "    Issue LDAP search using filter")
3808                 },
3809                 {
3810                         "dn",
3811                         net_ads_dn,
3812                         NET_TRANSPORT_ADS,
3813                         N_("Issue LDAP search by DN"),
3814                         N_("net ads dn\n"
3815                            "    Issue LDAP search by DN")
3816                 },
3817                 {
3818                         "sid",
3819                         net_ads_sid,
3820                         NET_TRANSPORT_ADS,
3821                         N_("Issue LDAP search by SID"),
3822                         N_("net ads sid\n"
3823                            "    Issue LDAP search by SID")
3824                 },
3825                 {
3826                         "workgroup",
3827                         net_ads_workgroup,
3828                         NET_TRANSPORT_ADS,
3829                         N_("Display workgroup name"),
3830                         N_("net ads workgroup\n"
3831                            "    Display the workgroup name")
3832                 },
3833                 {
3834                         "lookup",
3835                         net_ads_lookup,
3836                         NET_TRANSPORT_ADS,
3837                         N_("Perform CLDAP query on DC"),
3838                         N_("net ads lookup\n"
3839                            "    Find the ADS DC using CLDAP lookups")
3840                 },
3841                 {
3842                         "keytab",
3843                         net_ads_keytab,
3844                         NET_TRANSPORT_ADS,
3845                         N_("Manage local keytab file"),
3846                         N_("net ads keytab\n"
3847                            "    Manage local keytab file")
3848                 },
3849                 {
3850                         "setspn",
3851                         net_ads_setspn,
3852                         NET_TRANSPORT_ADS,
3853                         N_("Manage Service Principal Names (SPN)s"),
3854                         N_("net ads spnset\n"
3855                            "    Manage Service Principal Names (SPN)s")
3856                 },
3857                 {
3858                         "gpo",
3859                         net_ads_gpo,
3860                         NET_TRANSPORT_ADS,
3861                         N_("Manage group policy objects"),
3862                         N_("net ads gpo\n"
3863                            "    Manage group policy objects")
3864                 },
3865                 {
3866                         "kerberos",
3867                         net_ads_kerberos,
3868                         NET_TRANSPORT_ADS,
3869                         N_("Manage kerberos keytab"),
3870                         N_("net ads kerberos\n"
3871                            "    Manage kerberos keytab")
3872                 },
3873                 {
3874                         "enctypes",
3875                         net_ads_enctypes,
3876                         NET_TRANSPORT_ADS,
3877                         N_("List/modify supported encryption types"),
3878                         N_("net ads enctypes\n"
3879                            "    List/modify enctypes")
3880                 },
3881                 {NULL, NULL, 0, NULL, NULL}
3882         };
3883
3884         return net_run_function(c, argc, argv, "net ads", func);
3885 }
3886
3887 #else
3888
3889 static int net_ads_noads(void)
3890 {
3891         d_fprintf(stderr, _("ADS support not compiled in\n"));
3892         return -1;
3893 }
3894
3895 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3896 {
3897         return net_ads_noads();
3898 }
3899
3900 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3901 {
3902         return net_ads_noads();
3903 }
3904
3905 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3906 {
3907         return net_ads_noads();
3908 }
3909
3910 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3911 {
3912         return net_ads_noads();
3913 }
3914
3915 int net_ads_join(struct net_context *c, int argc, const char **argv)
3916 {
3917         return net_ads_noads();
3918 }
3919
3920 int net_ads_user(struct net_context *c, int argc, const char **argv)
3921 {
3922         return net_ads_noads();
3923 }
3924
3925 int net_ads_group(struct net_context *c, int argc, const char **argv)
3926 {
3927         return net_ads_noads();
3928 }
3929
3930 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3931 {
3932         return net_ads_noads();
3933 }
3934
3935 /* this one shouldn't display a message */
3936 int net_ads_check(struct net_context *c)
3937 {
3938         return -1;
3939 }
3940
3941 int net_ads_check_our_domain(struct net_context *c)
3942 {
3943         return -1;
3944 }
3945
3946 int net_ads(struct net_context *c, int argc, const char **argv)
3947 {
3948         return net_ads_noads();
3949 }
3950
3951 #endif  /* HAVE_ADS */