s3:net: Refactor net_ads_printer_publish(), 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         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1840         ADS_STRUCT *ads = NULL;
1841         ADS_STATUS status;
1842         NTSTATUS ntstatus;
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         int ret = -1;
1849
1850 #ifdef DEVELOPER
1851         talloc_enable_leak_report();
1852 #endif
1853
1854         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1855                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1856                                     "detection of addresses in a clustered "
1857                                     "setup.\n"));
1858                 c->display_usage = true;
1859         }
1860
1861         if (c->display_usage) {
1862                 d_printf(  "%s\n"
1863                            "net ads dns register [hostname [IP [IP...]]]\n"
1864                            "    %s\n",
1865                          _("Usage:"),
1866                          _("Register hostname with DNS\n"));
1867                 TALLOC_FREE(tmp_ctx);
1868                 return -1;
1869         }
1870
1871         if (argc >= 1) {
1872                 hostname = argv[0];
1873         }
1874
1875         if (argc > 1) {
1876                 num_addrs = argc - 1;
1877                 addrs_list = &argv[1];
1878         } else if (lp_clustering()) {
1879                 addrs_list = lp_cluster_addresses();
1880                 num_addrs = str_list_length(addrs_list);
1881         }
1882
1883         if (num_addrs > 0) {
1884                 addrs = talloc_zero_array(tmp_ctx,
1885                                           struct sockaddr_storage,
1886                                           num_addrs);
1887                 if (addrs == NULL) {
1888                         d_fprintf(stderr, _("Error allocating memory!\n"));
1889                         goto out;
1890                 }
1891         }
1892
1893         for (count = 0; count < num_addrs; count++) {
1894                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1895                         d_fprintf(stderr, "%s '%s'.\n",
1896                                           _("Cannot interpret address"),
1897                                           addrs_list[count]);
1898                         goto out;
1899                 }
1900         }
1901
1902         status = ads_startup(c, true, &ads);
1903         if ( !ADS_ERR_OK(status) ) {
1904                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1905                 goto out;
1906         }
1907
1908         ntstatus = net_update_dns_ext(c,
1909                                       tmp_ctx,
1910                                       ads,
1911                                       hostname,
1912                                       addrs,
1913                                       num_addrs,
1914                                       false);
1915         if (!NT_STATUS_IS_OK(ntstatus)) {
1916                 d_fprintf( stderr, _("DNS update failed!\n") );
1917                 goto out;
1918         }
1919
1920         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1921
1922         ret = 0;
1923 out:
1924         ads_destroy(&ads);
1925         TALLOC_FREE(tmp_ctx);
1926
1927         return ret;
1928 #else
1929         d_fprintf(stderr,
1930                   _("DNS update support not enabled at compile time!\n"));
1931         return -1;
1932 #endif
1933 }
1934
1935 static int net_ads_dns_unregister(struct net_context *c,
1936                                   int argc,
1937                                   const char **argv)
1938 {
1939 #if defined(HAVE_KRB5)
1940         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1941         ADS_STRUCT *ads = NULL;
1942         ADS_STATUS status;
1943         NTSTATUS ntstatus;
1944         const char *hostname = NULL;
1945         int ret = -1;
1946
1947 #ifdef DEVELOPER
1948         talloc_enable_leak_report();
1949 #endif
1950
1951         if (argc != 1) {
1952                 c->display_usage = true;
1953         }
1954
1955         if (c->display_usage) {
1956                 d_printf(  "%s\n"
1957                            "net ads dns unregister [hostname]\n"
1958                            "    %s\n",
1959                          _("Usage:"),
1960                          _("Remove all IP Address entires for a given\n"
1961                            "    hostname from the Active Directory server.\n"));
1962                 TALLOC_FREE(tmp_ctx);
1963                 return -1;
1964         }
1965
1966         /* Get the hostname for un-registering */
1967         hostname = argv[0];
1968
1969         status = ads_startup(c, true, &ads);
1970         if ( !ADS_ERR_OK(status) ) {
1971                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1972                 goto out;
1973         }
1974
1975         ntstatus = net_update_dns_ext(c,
1976                                       tmp_ctx,
1977                                       ads,
1978                                       hostname,
1979                                       NULL,
1980                                       0,
1981                                       true);
1982         if (!NT_STATUS_IS_OK(ntstatus)) {
1983                 d_fprintf( stderr, _("DNS update failed!\n") );
1984                 goto out;
1985         }
1986
1987         d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1988
1989         ret = 0;
1990 out:
1991         ads_destroy(&ads);
1992         TALLOC_FREE(tmp_ctx);
1993
1994         return ret;
1995 #else
1996         d_fprintf(stderr,
1997                   _("DNS update support not enabled at compile time!\n"));
1998         return -1;
1999 #endif
2000 }
2001
2002
2003 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2004 {
2005         size_t num_names = 0;
2006         char **hostnames = NULL;
2007         size_t i = 0;
2008         struct samba_sockaddr *addrs = NULL;
2009         NTSTATUS status;
2010
2011         if (argc != 1 || c->display_usage) {
2012                 d_printf(  "%s\n"
2013                            "    %s\n"
2014                            "    %s\n",
2015                          _("Usage:"),
2016                          _("net ads dns async <name>\n"),
2017                          _("  Async look up hostname from the DNS server\n"
2018                            "    hostname\tName to look up\n"));
2019                 return -1;
2020         }
2021
2022         status = ads_dns_lookup_a(talloc_tos(),
2023                                   argv[0],
2024                                   &num_names,
2025                                   &hostnames,
2026                                   &addrs);
2027         if (!NT_STATUS_IS_OK(status)) {
2028                 d_printf("Looking up A record for %s got error %s\n",
2029                          argv[0],
2030                          nt_errstr(status));
2031                 return -1;
2032         }
2033         d_printf("Async A record lookup - got %u names for %s\n",
2034                  (unsigned int)num_names,
2035                  argv[0]);
2036         for (i = 0; i < num_names; i++) {
2037                 char addr_buf[INET6_ADDRSTRLEN];
2038                 print_sockaddr(addr_buf,
2039                                sizeof(addr_buf),
2040                                &addrs[i].u.ss);
2041                 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2042                         (unsigned int)i,
2043                         hostnames[i],
2044                         addr_buf);
2045         }
2046
2047 #if defined(HAVE_IPV6)
2048         status = ads_dns_lookup_aaaa(talloc_tos(),
2049                                      argv[0],
2050                                      &num_names,
2051                                      &hostnames,
2052                                      &addrs);
2053         if (!NT_STATUS_IS_OK(status)) {
2054                 d_printf("Looking up AAAA record for %s got error %s\n",
2055                          argv[0],
2056                          nt_errstr(status));
2057                 return -1;
2058         }
2059         d_printf("Async AAAA record lookup - got %u names for %s\n",
2060                  (unsigned int)num_names,
2061                  argv[0]);
2062         for (i = 0; i < num_names; i++) {
2063                 char addr_buf[INET6_ADDRSTRLEN];
2064                 print_sockaddr(addr_buf,
2065                                sizeof(addr_buf),
2066                                &addrs[i].u.ss);
2067                 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2068                         (unsigned int)i,
2069                         hostnames[i],
2070                         addr_buf);
2071         }
2072 #endif
2073         return 0;
2074 }
2075
2076
2077 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2078 {
2079         struct functable func[] = {
2080                 {
2081                         "register",
2082                         net_ads_dns_register,
2083                         NET_TRANSPORT_ADS,
2084                         N_("Add host dns entry to AD"),
2085                         N_("net ads dns register\n"
2086                            "    Add host dns entry to AD")
2087                 },
2088                 {
2089                         "unregister",
2090                         net_ads_dns_unregister,
2091                         NET_TRANSPORT_ADS,
2092                         N_("Remove host dns entry from AD"),
2093                         N_("net ads dns unregister\n"
2094                            "    Remove host dns entry from AD")
2095                 },
2096                 {
2097                         "async",
2098                         net_ads_dns_async,
2099                         NET_TRANSPORT_ADS,
2100                         N_("Look up host"),
2101                         N_("net ads dns async\n"
2102                            "    Look up host using async DNS")
2103                 },
2104                 {NULL, NULL, 0, NULL, NULL}
2105         };
2106
2107         return net_run_function(c, argc, argv, "net ads dns", func);
2108 }
2109
2110 /*******************************************************************
2111  ********************************************************************/
2112
2113 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2114 {
2115         d_printf(_(
2116 "\nnet ads printer search <printer>"
2117 "\n\tsearch for a printer in the directory\n"
2118 "\nnet ads printer info <printer> <server>"
2119 "\n\tlookup info in directory for printer on server"
2120 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2121 "\nnet ads printer publish <printername>"
2122 "\n\tpublish printer in directory"
2123 "\n\t(note: printer name is required)\n"
2124 "\nnet ads printer remove <printername>"
2125 "\n\tremove printer from directory"
2126 "\n\t(note: printer name is required)\n"));
2127         return -1;
2128 }
2129
2130 /*******************************************************************
2131  ********************************************************************/
2132
2133 static int net_ads_printer_search(struct net_context *c,
2134                                   int argc,
2135                                   const char **argv)
2136 {
2137         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2138         ADS_STRUCT *ads = NULL;
2139         ADS_STATUS status;
2140         LDAPMessage *res = NULL;
2141         int ret = -1;
2142
2143         if (c->display_usage) {
2144                 d_printf(  "%s\n"
2145                            "net ads printer search\n"
2146                            "    %s\n",
2147                          _("Usage:"),
2148                          _("List printers in the AD"));
2149                 TALLOC_FREE(tmp_ctx);
2150                 return 0;
2151         }
2152
2153         status = ads_startup(c, false, &ads);
2154         if (!ADS_ERR_OK(status)) {
2155                 goto out;
2156         }
2157
2158         status = ads_find_printers(ads, &res);
2159         if (!ADS_ERR_OK(status)) {
2160                 d_fprintf(stderr, _("ads_find_printer: %s\n"),
2161                           ads_errstr(status));
2162                 goto out;
2163         }
2164
2165         if (ads_count_replies(ads, res) == 0) {
2166                 d_fprintf(stderr, _("No results found\n"));
2167                 goto out;
2168         }
2169
2170         ads_dump(ads, res);
2171
2172         ret = 0;
2173 out:
2174         ads_msgfree(ads, res);
2175         ads_destroy(&ads);
2176         TALLOC_FREE(tmp_ctx);
2177         return ret;
2178 }
2179
2180 static int net_ads_printer_info(struct net_context *c,
2181                                 int argc,
2182                                 const char **argv)
2183 {
2184         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2185         ADS_STRUCT *ads = NULL;
2186         ADS_STATUS status;
2187         const char *servername = NULL;
2188         const char *printername = NULL;
2189         LDAPMessage *res = NULL;
2190         int ret = -1;
2191
2192         if (c->display_usage) {
2193                 d_printf("%s\n%s",
2194                          _("Usage:"),
2195                          _("net ads printer info [printername [servername]]\n"
2196                            "  Display printer info from AD\n"
2197                            "    printername\tPrinter name or wildcard\n"
2198                            "    servername\tName of the print server\n"));
2199                 TALLOC_FREE(tmp_ctx);
2200                 return 0;
2201         }
2202
2203         status = ads_startup(c, false, &ads);
2204         if (!ADS_ERR_OK(status)) {
2205                 goto out;
2206         }
2207
2208         if (argc > 0) {
2209                 printername = argv[0];
2210         } else {
2211                 printername = "*";
2212         }
2213
2214         if (argc > 1) {
2215                 servername =  argv[1];
2216         } else {
2217                 servername = lp_netbios_name();
2218         }
2219
2220         status = ads_find_printer_on_server(ads, &res, printername, servername);
2221         if (!ADS_ERR_OK(status)) {
2222                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2223                           servername, ads_errstr(status));
2224                 goto out;
2225         }
2226
2227         if (ads_count_replies(ads, res) == 0) {
2228                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2229                 goto out;
2230         }
2231
2232         ads_dump(ads, res);
2233
2234         ret = 0;
2235 out:
2236         ads_msgfree(ads, res);
2237         ads_destroy(&ads);
2238         TALLOC_FREE(tmp_ctx);
2239         return ret;
2240 }
2241
2242 static int net_ads_printer_publish(struct net_context *c,
2243                                    int argc,
2244                                    const char **argv)
2245 {
2246         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2247         ADS_STRUCT *ads = NULL;
2248         ADS_STATUS status;
2249         const char *servername = NULL;
2250         const char *printername = NULL;
2251         struct cli_state *cli = NULL;
2252         struct rpc_pipe_client *pipe_hnd = NULL;
2253         struct sockaddr_storage server_ss = { 0 };
2254         NTSTATUS nt_status;
2255         ADS_MODLIST mods = NULL;
2256         char *prt_dn = NULL;
2257         char *srv_dn = NULL;
2258         char **srv_cn = NULL;
2259         char *srv_cn_escaped = NULL;
2260         char *printername_escaped = NULL;
2261         LDAPMessage *res = NULL;
2262         bool ok;
2263         int ret = -1;
2264
2265         if (argc < 1 || c->display_usage) {
2266                 d_printf("%s\n%s",
2267                          _("Usage:"),
2268                          _("net ads printer publish <printername> [servername]\n"
2269                            "  Publish printer in AD\n"
2270                            "    printername\tName of the printer\n"
2271                            "    servername\tName of the print server\n"));
2272                 TALLOC_FREE(tmp_ctx);
2273                 return -1;
2274         }
2275
2276         mods = ads_init_mods(tmp_ctx);
2277         if (mods == NULL) {
2278                 d_fprintf(stderr, _("Out of memory\n"));
2279                 goto out;
2280         }
2281
2282         status = ads_startup(c, true, &ads);
2283         if (!ADS_ERR_OK(status)) {
2284                 goto out;
2285         }
2286
2287         printername = argv[0];
2288
2289         if (argc == 2) {
2290                 servername = argv[1];
2291         } else {
2292                 servername = lp_netbios_name();
2293         }
2294
2295         /* Get printer data from SPOOLSS */
2296
2297         ok = resolve_name(servername, &server_ss, 0x20, false);
2298         if (!ok) {
2299                 d_fprintf(stderr, _("Could not find server %s\n"),
2300                           servername);
2301                 goto out;
2302         }
2303
2304         cli_credentials_set_kerberos_state(c->creds,
2305                                            CRED_USE_KERBEROS_REQUIRED,
2306                                            CRED_SPECIFIED);
2307
2308         nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2309                                         &server_ss, 0,
2310                                         "IPC$", "IPC",
2311                                         c->creds,
2312                                         CLI_FULL_CONNECTION_IPC);
2313
2314         if (NT_STATUS_IS_ERR(nt_status)) {
2315                 d_fprintf(stderr, _("Unable to open a connection to %s to "
2316                                     "obtain data for %s\n"),
2317                           servername, printername);
2318                 goto out;
2319         }
2320
2321         /* Publish on AD server */
2322
2323         ads_find_machine_acct(ads, &res, servername);
2324
2325         if (ads_count_replies(ads, res) == 0) {
2326                 d_fprintf(stderr, _("Could not find machine account for server "
2327                                     "%s\n"),
2328                          servername);
2329                 goto out;
2330         }
2331
2332         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2333         srv_cn = ldap_explode_dn(srv_dn, 1);
2334
2335         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2336         printername_escaped = escape_rdn_val_string_alloc(printername);
2337         if (!srv_cn_escaped || !printername_escaped) {
2338                 SAFE_FREE(srv_cn_escaped);
2339                 SAFE_FREE(printername_escaped);
2340                 d_fprintf(stderr, _("Internal error, out of memory!"));
2341                 goto out;
2342         }
2343
2344         prt_dn = talloc_asprintf(tmp_ctx,
2345                                  "cn=%s-%s,%s",
2346                                  srv_cn_escaped,
2347                                  printername_escaped,
2348                                  srv_dn);
2349         if (prt_dn == NULL) {
2350                 SAFE_FREE(srv_cn_escaped);
2351                 SAFE_FREE(printername_escaped);
2352                 d_fprintf(stderr, _("Internal error, out of memory!"));
2353                 goto out;
2354         }
2355
2356         SAFE_FREE(srv_cn_escaped);
2357         SAFE_FREE(printername_escaped);
2358
2359         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2360         if (!NT_STATUS_IS_OK(nt_status)) {
2361                 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2362                          servername);
2363                 goto out;
2364         }
2365
2366         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd,
2367                                                               tmp_ctx,
2368                                                               &mods,
2369                                                               printername))) {
2370                 goto out;
2371         }
2372
2373         status = ads_add_printer_entry(ads, prt_dn, tmp_ctx, &mods);
2374         if (!ADS_ERR_OK(status)) {
2375                 d_fprintf(stderr, "ads_publish_printer: %s\n",
2376                           ads_errstr(status));
2377                 goto out;
2378         }
2379
2380         d_printf("published printer\n");
2381
2382         ret = 0;
2383 out:
2384         ads_destroy(&ads);
2385         talloc_destroy(tmp_ctx);
2386
2387         return ret;
2388 }
2389
2390 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2391 {
2392         ADS_STRUCT *ads;
2393         ADS_STATUS rc;
2394         const char *servername;
2395         char *prt_dn;
2396         LDAPMessage *res = NULL;
2397
2398         if (argc < 1 || c->display_usage) {
2399                 d_printf("%s\n%s",
2400                          _("Usage:"),
2401                          _("net ads printer remove <printername> [servername]\n"
2402                            "  Remove a printer from the AD\n"
2403                            "    printername\tName of the printer\n"
2404                            "    servername\tName of the print server\n"));
2405                 return -1;
2406         }
2407
2408         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2409                 return -1;
2410         }
2411
2412         if (argc > 1) {
2413                 servername = argv[1];
2414         } else {
2415                 servername = lp_netbios_name();
2416         }
2417
2418         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2419
2420         if (!ADS_ERR_OK(rc)) {
2421                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2422                 ads_msgfree(ads, res);
2423                 ads_destroy(&ads);
2424                 return -1;
2425         }
2426
2427         if (ads_count_replies(ads, res) == 0) {
2428                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2429                 ads_msgfree(ads, res);
2430                 ads_destroy(&ads);
2431                 return -1;
2432         }
2433
2434         prt_dn = ads_get_dn(ads, talloc_tos(), res);
2435         ads_msgfree(ads, res);
2436         rc = ads_del_dn(ads, prt_dn);
2437         TALLOC_FREE(prt_dn);
2438
2439         if (!ADS_ERR_OK(rc)) {
2440                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2441                 ads_destroy(&ads);
2442                 return -1;
2443         }
2444
2445         ads_destroy(&ads);
2446         return 0;
2447 }
2448
2449 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2450 {
2451         struct functable func[] = {
2452                 {
2453                         "search",
2454                         net_ads_printer_search,
2455                         NET_TRANSPORT_ADS,
2456                         N_("Search for a printer"),
2457                         N_("net ads printer search\n"
2458                            "    Search for a printer")
2459                 },
2460                 {
2461                         "info",
2462                         net_ads_printer_info,
2463                         NET_TRANSPORT_ADS,
2464                         N_("Display printer information"),
2465                         N_("net ads printer info\n"
2466                            "    Display printer information")
2467                 },
2468                 {
2469                         "publish",
2470                         net_ads_printer_publish,
2471                         NET_TRANSPORT_ADS,
2472                         N_("Publish a printer"),
2473                         N_("net ads printer publish\n"
2474                            "    Publish a printer")
2475                 },
2476                 {
2477                         "remove",
2478                         net_ads_printer_remove,
2479                         NET_TRANSPORT_ADS,
2480                         N_("Delete a printer"),
2481                         N_("net ads printer remove\n"
2482                            "    Delete a printer")
2483                 },
2484                 {NULL, NULL, 0, NULL, NULL}
2485         };
2486
2487         return net_run_function(c, argc, argv, "net ads printer", func);
2488 }
2489
2490
2491 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2492 {
2493         ADS_STRUCT *ads;
2494         const char *auth_principal = cli_credentials_get_username(c->creds);
2495         const char *auth_password = cli_credentials_get_password(c->creds);
2496         const char *realm = NULL;
2497         const char *new_password = NULL;
2498         char *chr, *prompt;
2499         const char *user;
2500         char pwd[256] = {0};
2501         ADS_STATUS ret;
2502
2503         if (c->display_usage) {
2504                 d_printf("%s\n%s",
2505                          _("Usage:"),
2506                          _("net ads password <username>\n"
2507                            "  Change password for user\n"
2508                            "    username\tName of user to change password for\n"));
2509                 return 0;
2510         }
2511
2512         if (auth_principal == NULL || auth_password == NULL) {
2513                 d_fprintf(stderr, _("You must supply an administrator "
2514                                     "username/password\n"));
2515                 return -1;
2516         }
2517
2518         if (argc < 1) {
2519                 d_fprintf(stderr, _("ERROR: You must say which username to "
2520                                     "change password for\n"));
2521                 return -1;
2522         }
2523
2524         user = argv[0];
2525         if (!strchr_m(user, '@')) {
2526                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2527                         return -1;
2528                 }
2529                 user = chr;
2530         }
2531
2532         use_in_memory_ccache();
2533         chr = strchr_m(auth_principal, '@');
2534         if (chr) {
2535                 realm = ++chr;
2536         } else {
2537                 realm = lp_realm();
2538         }
2539
2540         /* use the realm so we can eventually change passwords for users
2541         in realms other than default */
2542         ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2543         if (ads == NULL) {
2544                 return -1;
2545         }
2546
2547         /* we don't actually need a full connect, but it's the easy way to
2548                 fill in the KDC's addresss */
2549         ads_connect(ads);
2550
2551         if (!ads->config.realm) {
2552                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2553                 ads_destroy(&ads);
2554                 return -1;
2555         }
2556
2557         if (argv[1]) {
2558                 new_password = (const char *)argv[1];
2559         } else {
2560                 int rc;
2561
2562                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2563                         return -1;
2564                 }
2565                 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2566                 if (rc < 0) {
2567                         return -1;
2568                 }
2569                 new_password = pwd;
2570                 free(prompt);
2571         }
2572
2573         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2574                                 auth_password, user, new_password, ads->auth.time_offset);
2575         memset(pwd, '\0', sizeof(pwd));
2576         if (!ADS_ERR_OK(ret)) {
2577                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2578                 ads_destroy(&ads);
2579                 return -1;
2580         }
2581
2582         d_printf(_("Password change for %s completed.\n"), user);
2583         ads_destroy(&ads);
2584
2585         return 0;
2586 }
2587
2588 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2589 {
2590         ADS_STRUCT *ads;
2591         char *host_principal;
2592         fstring my_name;
2593         ADS_STATUS ret;
2594
2595         if (c->display_usage) {
2596                 d_printf(  "%s\n"
2597                            "net ads changetrustpw\n"
2598                            "    %s\n",
2599                          _("Usage:"),
2600                          _("Change the machine account's trust password"));
2601                 return 0;
2602         }
2603
2604         if (!secrets_init()) {
2605                 DEBUG(1,("Failed to initialise secrets database\n"));
2606                 return -1;
2607         }
2608
2609         net_use_krb_machine_account(c);
2610
2611         use_in_memory_ccache();
2612
2613         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2614                 return -1;
2615         }
2616
2617         fstrcpy(my_name, lp_netbios_name());
2618         if (!strlower_m(my_name)) {
2619                 ads_destroy(&ads);
2620                 return -1;
2621         }
2622
2623         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2624                 ads_destroy(&ads);
2625                 return -1;
2626         }
2627         d_printf(_("Changing password for principal: %s\n"), host_principal);
2628
2629         ret = ads_change_trust_account_password(ads, host_principal);
2630
2631         if (!ADS_ERR_OK(ret)) {
2632                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2633                 ads_destroy(&ads);
2634                 SAFE_FREE(host_principal);
2635                 return -1;
2636         }
2637
2638         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2639
2640         if (USE_SYSTEM_KEYTAB) {
2641                 d_printf(_("Attempting to update system keytab with new password.\n"));
2642                 if (ads_keytab_create_default(ads)) {
2643                         d_printf(_("Failed to update system keytab.\n"));
2644                 }
2645         }
2646
2647         ads_destroy(&ads);
2648         SAFE_FREE(host_principal);
2649
2650         return 0;
2651 }
2652
2653 /*
2654   help for net ads search
2655 */
2656 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2657 {
2658         d_printf(_(
2659                 "\nnet ads search <expression> <attributes...>\n"
2660                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2661                 "The expression is a standard LDAP search expression, and the\n"
2662                 "attributes are a list of LDAP fields to show in the results.\n\n"
2663                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2664                 ));
2665         net_common_flags_usage(c, argc, argv);
2666         return -1;
2667 }
2668
2669
2670 /*
2671   general ADS search function. Useful in diagnosing problems in ADS
2672 */
2673 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2674 {
2675         ADS_STRUCT *ads;
2676         ADS_STATUS rc;
2677         const char *ldap_exp;
2678         const char **attrs;
2679         LDAPMessage *res = NULL;
2680
2681         if (argc < 1 || c->display_usage) {
2682                 return net_ads_search_usage(c, argc, argv);
2683         }
2684
2685         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2686                 return -1;
2687         }
2688
2689         ldap_exp = argv[0];
2690         attrs = (argv + 1);
2691
2692         rc = ads_do_search_retry(ads, ads->config.bind_path,
2693                                LDAP_SCOPE_SUBTREE,
2694                                ldap_exp, attrs, &res);
2695         if (!ADS_ERR_OK(rc)) {
2696                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2697                 ads_destroy(&ads);
2698                 return -1;
2699         }
2700
2701         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2702
2703         /* dump the results */
2704         ads_dump(ads, res);
2705
2706         ads_msgfree(ads, res);
2707         ads_destroy(&ads);
2708
2709         return 0;
2710 }
2711
2712
2713 /*
2714   help for net ads search
2715 */
2716 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2717 {
2718         d_printf(_(
2719                 "\nnet ads dn <dn> <attributes...>\n"
2720                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2721                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2722                 "to show in the results\n\n"
2723                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2724                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2725                 ));
2726         net_common_flags_usage(c, argc, argv);
2727         return -1;
2728 }
2729
2730
2731 /*
2732   general ADS search function. Useful in diagnosing problems in ADS
2733 */
2734 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2735 {
2736         ADS_STRUCT *ads;
2737         ADS_STATUS rc;
2738         const char *dn;
2739         const char **attrs;
2740         LDAPMessage *res = NULL;
2741
2742         if (argc < 1 || c->display_usage) {
2743                 return net_ads_dn_usage(c, argc, argv);
2744         }
2745
2746         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2747                 return -1;
2748         }
2749
2750         dn = argv[0];
2751         attrs = (argv + 1);
2752
2753         rc = ads_do_search_all(ads, dn,
2754                                LDAP_SCOPE_BASE,
2755                                "(objectclass=*)", attrs, &res);
2756         if (!ADS_ERR_OK(rc)) {
2757                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2758                 ads_destroy(&ads);
2759                 return -1;
2760         }
2761
2762         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2763
2764         /* dump the results */
2765         ads_dump(ads, res);
2766
2767         ads_msgfree(ads, res);
2768         ads_destroy(&ads);
2769
2770         return 0;
2771 }
2772
2773 /*
2774   help for net ads sid search
2775 */
2776 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2777 {
2778         d_printf(_(
2779                 "\nnet ads sid <sid> <attributes...>\n"
2780                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2781                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2782                 "to show in the results\n\n"
2783                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2784                 ));
2785         net_common_flags_usage(c, argc, argv);
2786         return -1;
2787 }
2788
2789
2790 /*
2791   general ADS search function. Useful in diagnosing problems in ADS
2792 */
2793 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2794 {
2795         ADS_STRUCT *ads;
2796         ADS_STATUS rc;
2797         const char *sid_string;
2798         const char **attrs;
2799         LDAPMessage *res = NULL;
2800         struct dom_sid sid;
2801
2802         if (argc < 1 || c->display_usage) {
2803                 return net_ads_sid_usage(c, argc, argv);
2804         }
2805
2806         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2807                 return -1;
2808         }
2809
2810         sid_string = argv[0];
2811         attrs = (argv + 1);
2812
2813         if (!string_to_sid(&sid, sid_string)) {
2814                 d_fprintf(stderr, _("could not convert sid\n"));
2815                 ads_destroy(&ads);
2816                 return -1;
2817         }
2818
2819         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2820         if (!ADS_ERR_OK(rc)) {
2821                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2822                 ads_destroy(&ads);
2823                 return -1;
2824         }
2825
2826         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2827
2828         /* dump the results */
2829         ads_dump(ads, res);
2830
2831         ads_msgfree(ads, res);
2832         ads_destroy(&ads);
2833
2834         return 0;
2835 }
2836
2837 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2838 {
2839         int ret;
2840         ADS_STRUCT *ads;
2841
2842         if (c->display_usage) {
2843                 d_printf(  "%s\n"
2844                            "net ads keytab flush\n"
2845                            "    %s\n",
2846                          _("Usage:"),
2847                          _("Delete the whole keytab"));
2848                 return 0;
2849         }
2850
2851         if (!c->opt_user_specified && c->opt_password == NULL) {
2852                 net_use_krb_machine_account(c);
2853         }
2854
2855         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2856                 return -1;
2857         }
2858         ret = ads_keytab_flush(ads);
2859         ads_destroy(&ads);
2860         return ret;
2861 }
2862
2863 static int net_ads_keytab_add(struct net_context *c,
2864                               int argc,
2865                               const char **argv,
2866                               bool update_ads)
2867 {
2868         int i;
2869         int ret = 0;
2870         ADS_STRUCT *ads;
2871
2872         if (c->display_usage) {
2873                 d_printf("%s\n%s",
2874                          _("Usage:"),
2875                          _("net ads keytab add <principal> [principal ...]\n"
2876                            "  Add principals to local keytab\n"
2877                            "    principal\tKerberos principal to add to "
2878                            "keytab\n"));
2879                 return 0;
2880         }
2881
2882         d_printf(_("Processing principals to add...\n"));
2883
2884         if (!c->opt_user_specified && c->opt_password == NULL) {
2885                 net_use_krb_machine_account(c);
2886         }
2887
2888         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2889                 return -1;
2890         }
2891         for (i = 0; i < argc; i++) {
2892                 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2893         }
2894         ads_destroy(&ads);
2895         return ret;
2896 }
2897
2898 static int net_ads_keytab_add_default(struct net_context *c,
2899                                       int argc,
2900                                       const char **argv)
2901 {
2902         return net_ads_keytab_add(c, argc, argv, false);
2903 }
2904
2905 static int net_ads_keytab_add_update_ads(struct net_context *c,
2906                                          int argc,
2907                                          const char **argv)
2908 {
2909         return net_ads_keytab_add(c, argc, argv, true);
2910 }
2911
2912 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2913 {
2914         ADS_STRUCT *ads;
2915         int ret;
2916
2917         if (c->display_usage) {
2918                 d_printf(  "%s\n"
2919                            "net ads keytab create\n"
2920                            "    %s\n",
2921                          _("Usage:"),
2922                          _("Create new default keytab"));
2923                 return 0;
2924         }
2925
2926         if (!c->opt_user_specified && c->opt_password == NULL) {
2927                 net_use_krb_machine_account(c);
2928         }
2929
2930         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2931                 return -1;
2932         }
2933         ret = ads_keytab_create_default(ads);
2934         ads_destroy(&ads);
2935         return ret;
2936 }
2937
2938 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2939 {
2940         const char *keytab = NULL;
2941
2942         if (c->display_usage) {
2943                 d_printf("%s\n%s",
2944                          _("Usage:"),
2945                          _("net ads keytab list [keytab]\n"
2946                            "  List a local keytab\n"
2947                            "    keytab\tKeytab to list\n"));
2948                 return 0;
2949         }
2950
2951         if (argc >= 1) {
2952                 keytab = argv[0];
2953         }
2954
2955         return ads_keytab_list(keytab);
2956 }
2957
2958
2959 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2960 {
2961         struct functable func[] = {
2962                 {
2963                         "add",
2964                         net_ads_keytab_add_default,
2965                         NET_TRANSPORT_ADS,
2966                         N_("Add a service principal"),
2967                         N_("net ads keytab add\n"
2968                            "    Add a service principal, updates keytab file only.")
2969                 },
2970                 {
2971                         "add_update_ads",
2972                         net_ads_keytab_add_update_ads,
2973                         NET_TRANSPORT_ADS,
2974                         N_("Add a service principal"),
2975                         N_("net ads keytab add_update_ads\n"
2976                            "    Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2977                 },
2978                 {
2979                         "create",
2980                         net_ads_keytab_create,
2981                         NET_TRANSPORT_ADS,
2982                         N_("Create a fresh keytab"),
2983                         N_("net ads keytab create\n"
2984                            "    Create a fresh keytab or update existing one.")
2985                 },
2986                 {
2987                         "flush",
2988                         net_ads_keytab_flush,
2989                         NET_TRANSPORT_ADS,
2990                         N_("Remove all keytab entries"),
2991                         N_("net ads keytab flush\n"
2992                            "    Remove all keytab entries")
2993                 },
2994                 {
2995                         "list",
2996                         net_ads_keytab_list,
2997                         NET_TRANSPORT_ADS,
2998                         N_("List a keytab"),
2999                         N_("net ads keytab list\n"
3000                            "    List a keytab")
3001                 },
3002                 {NULL, NULL, 0, NULL, NULL}
3003         };
3004
3005         if (!USE_KERBEROS_KEYTAB) {
3006                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3007                     "keytab method to use keytab functions.\n"));
3008         }
3009
3010         return net_run_function(c, argc, argv, "net ads keytab", func);
3011 }
3012
3013 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3014 {
3015         int ret = -1;
3016
3017         if (c->display_usage) {
3018                 d_printf(  "%s\n"
3019                            "net ads kerberos renew\n"
3020                            "    %s\n",
3021                          _("Usage:"),
3022                          _("Renew TGT from existing credential cache"));
3023                 return 0;
3024         }
3025
3026         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3027         if (ret) {
3028                 d_printf(_("failed to renew kerberos ticket: %s\n"),
3029                         error_message(ret));
3030         }
3031         return ret;
3032 }
3033
3034 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3035                                        struct PAC_DATA_CTR **pac_data_ctr)
3036 {
3037         NTSTATUS status;
3038         int ret = -1;
3039         const char *impersonate_princ_s = NULL;
3040         const char *local_service = NULL;
3041         int i;
3042
3043         for (i=0; i<argc; i++) {
3044                 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3045                         impersonate_princ_s = get_string_param(argv[i]);
3046                         if (impersonate_princ_s == NULL) {
3047                                 return -1;
3048                         }
3049                 }
3050                 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3051                         local_service = get_string_param(argv[i]);
3052                         if (local_service == NULL) {
3053                                 return -1;
3054                         }
3055                 }
3056         }
3057
3058         if (local_service == NULL) {
3059                 local_service = talloc_asprintf(c, "%s$@%s",
3060                                                 lp_netbios_name(), lp_realm());
3061                 if (local_service == NULL) {
3062                         goto out;
3063                 }
3064         }
3065
3066         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3067
3068         status = kerberos_return_pac(c,
3069                                      c->opt_user_name,
3070                                      c->opt_password,
3071                                      0,
3072                                      NULL,
3073                                      NULL,
3074                                      NULL,
3075                                      true,
3076                                      true,
3077                                      2592000, /* one month */
3078                                      impersonate_princ_s,
3079                                      local_service,
3080                                      NULL,
3081                                      NULL,
3082                                      pac_data_ctr);
3083         if (!NT_STATUS_IS_OK(status)) {
3084                 d_printf(_("failed to query kerberos PAC: %s\n"),
3085                         nt_errstr(status));
3086                 goto out;
3087         }
3088
3089         ret = 0;
3090  out:
3091         return ret;
3092 }
3093
3094 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3095 {
3096         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3097         int i, num_buffers;
3098         int ret = -1;
3099         enum PAC_TYPE type = 0;
3100
3101         if (c->display_usage) {
3102                 d_printf(  "%s\n"
3103                            "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3104                            "    %s\n",
3105                          _("Usage:"),
3106                          _("Dump the Kerberos PAC"));
3107                 return -1;
3108         }
3109
3110         for (i=0; i<argc; i++) {
3111                 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3112                         type = get_int_param(argv[i]);
3113                 }
3114         }
3115
3116         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3117         if (ret) {
3118                 return ret;
3119         }
3120
3121         if (type == 0) {
3122
3123                 char *s = NULL;
3124
3125                 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3126                         pac_data_ctr->pac_data);
3127                 if (s != NULL) {
3128                         d_printf(_("The Pac: %s\n"), s);
3129                         talloc_free(s);
3130                 }
3131
3132                 return 0;
3133         }
3134
3135         num_buffers = pac_data_ctr->pac_data->num_buffers;
3136
3137         for (i=0; i<num_buffers; i++) {
3138
3139                 char *s = NULL;
3140
3141                 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3142                         continue;
3143                 }
3144
3145                 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3146                                 pac_data_ctr->pac_data->buffers[i].info);
3147                 if (s != NULL) {
3148                         d_printf(_("The Pac: %s\n"), s);
3149                         talloc_free(s);
3150                 }
3151                 break;
3152         }
3153
3154         return 0;
3155 }
3156
3157 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3158 {
3159         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3160         char *filename = NULL;
3161         int ret = -1;
3162         int i;
3163
3164         if (c->display_usage) {
3165                 d_printf(  "%s\n"
3166                            "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3167                            "    %s\n",
3168                          _("Usage:"),
3169                          _("Save the Kerberos PAC"));
3170                 return -1;
3171         }
3172
3173         for (i=0; i<argc; i++) {
3174                 if (strnequal(argv[i], "filename", strlen("filename"))) {
3175                         filename = get_string_param(argv[i]);
3176                         if (filename == NULL) {
3177                                 return -1;
3178                         }
3179                 }
3180         }
3181
3182         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3183         if (ret) {
3184                 return ret;
3185         }
3186
3187         if (filename == NULL) {
3188                 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3189                 return -1;
3190         }
3191
3192         /* save the raw format */
3193         if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3194                 d_printf(_("failed to save PAC in %s\n"), filename);
3195                 return -1;
3196         }
3197
3198         return 0;
3199 }
3200
3201 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3202 {
3203         struct functable func[] = {
3204                 {
3205                         "dump",
3206                         net_ads_kerberos_pac_dump,
3207                         NET_TRANSPORT_ADS,
3208                         N_("Dump Kerberos PAC"),
3209                         N_("net ads kerberos pac dump\n"
3210                            "    Dump a Kerberos PAC to stdout")
3211                 },
3212                 {
3213                         "save",
3214                         net_ads_kerberos_pac_save,
3215                         NET_TRANSPORT_ADS,
3216                         N_("Save Kerberos PAC"),
3217                         N_("net ads kerberos pac save\n"
3218                            "    Save a Kerberos PAC in a file")
3219                 },
3220
3221                 {NULL, NULL, 0, NULL, NULL}
3222         };
3223
3224         return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3225 }
3226
3227 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3228 {
3229         TALLOC_CTX *mem_ctx = NULL;
3230         int ret = -1;
3231         NTSTATUS status;
3232
3233         if (c->display_usage) {
3234                 d_printf(  "%s\n"
3235                            "net ads kerberos kinit\n"
3236                            "    %s\n",
3237                          _("Usage:"),
3238                          _("Get Ticket Granting Ticket (TGT) for the user"));
3239                 return 0;
3240         }
3241
3242         mem_ctx = talloc_init("net_ads_kerberos_kinit");
3243         if (!mem_ctx) {
3244                 goto out;
3245         }
3246
3247         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3248
3249         ret = kerberos_kinit_password_ext(c->opt_user_name,
3250                                           c->opt_password,
3251                                           0,
3252                                           NULL,
3253                                           NULL,
3254                                           NULL,
3255                                           true,
3256                                           true,
3257                                           2592000, /* one month */
3258                                           NULL,
3259                                           NULL,
3260                                           NULL,
3261                                           &status);
3262         if (ret) {
3263                 d_printf(_("failed to kinit password: %s\n"),
3264                         nt_errstr(status));
3265         }
3266  out:
3267         return ret;
3268 }
3269
3270 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3271 {
3272         struct functable func[] = {
3273                 {
3274                         "kinit",
3275                         net_ads_kerberos_kinit,
3276                         NET_TRANSPORT_ADS,
3277                         N_("Retrieve Ticket Granting Ticket (TGT)"),
3278                         N_("net ads kerberos kinit\n"
3279                            "    Receive Ticket Granting Ticket (TGT)")
3280                 },
3281                 {
3282                         "renew",
3283                         net_ads_kerberos_renew,
3284                         NET_TRANSPORT_ADS,
3285                         N_("Renew Ticket Granting Ticket from credential cache"),
3286                         N_("net ads kerberos renew\n"
3287                            "    Renew Ticket Granting Ticket (TGT) from "
3288                            "credential cache")
3289                 },
3290                 {
3291                         "pac",
3292                         net_ads_kerberos_pac,
3293                         NET_TRANSPORT_ADS,
3294                         N_("Dump Kerberos PAC"),
3295                         N_("net ads kerberos pac\n"
3296                            "    Dump Kerberos PAC")
3297                 },
3298                 {NULL, NULL, 0, NULL, NULL}
3299         };
3300
3301         return net_run_function(c, argc, argv, "net ads kerberos", func);
3302 }
3303
3304 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3305 {
3306         int ret = 0;
3307         bool ok = false;
3308         ADS_STRUCT *ads = NULL;
3309         if (c->display_usage) {
3310                 d_printf("%s\n%s",
3311                          _("Usage:"),
3312                          _("net ads setspn list <machinename>\n"));
3313                 ret = 0;
3314                 goto done;
3315         }
3316         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3317                 ret = -1;
3318                 goto done;
3319         }
3320         if (argc) {
3321                 ok = ads_setspn_list(ads, argv[0]);
3322         } else {
3323                 ok = ads_setspn_list(ads, lp_netbios_name());
3324         }
3325         if (!ok) {
3326             ret = -1;
3327         }
3328 done:
3329         if (ads) {
3330                 ads_destroy(&ads);
3331         }
3332         return ret;
3333 }
3334
3335 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3336 {
3337         int ret = 0;
3338         bool ok = false;
3339         ADS_STRUCT *ads = NULL;
3340         if (c->display_usage || argc < 1) {
3341                 d_printf("%s\n%s",
3342                          _("Usage:"),
3343                          _("net ads setspn add <machinename> SPN\n"));
3344                 ret = 0;
3345                 goto done;
3346         }
3347         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3348                 ret = -1;
3349                 goto done;
3350         }
3351         if (argc > 1) {
3352                 ok = ads_setspn_add(ads, argv[0], argv[1]);
3353         } else {
3354                 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3355         }
3356         if (!ok) {
3357             ret = -1;
3358         }
3359 done:
3360         if (ads) {
3361                 ads_destroy(&ads);
3362         }
3363         return ret;
3364 }
3365
3366 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3367 {
3368         int ret = 0;
3369         bool ok = false;
3370         ADS_STRUCT *ads = NULL;
3371         if (c->display_usage || argc < 1) {
3372                 d_printf("%s\n%s",
3373                          _("Usage:"),
3374                          _("net ads setspn delete <machinename> SPN\n"));
3375                 ret = 0;
3376                 goto done;
3377         }
3378         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3379                 ret = -1;
3380                 goto done;
3381         }
3382         if (argc > 1) {
3383                 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3384         } else {
3385                 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3386         }
3387         if (!ok) {
3388                 ret = -1;
3389         }
3390 done:
3391         if (ads) {
3392                 ads_destroy(&ads);
3393         }
3394         return ret;
3395 }
3396
3397 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3398 {
3399         struct functable func[] = {
3400                 {
3401                         "list",
3402                         net_ads_setspn_list,
3403                         NET_TRANSPORT_ADS,
3404                         N_("List Service Principal Names (SPN)"),
3405                         N_("net ads setspn list machine\n"
3406                            "    List Service Principal Names (SPN)")
3407                 },
3408                 {
3409                         "add",
3410                         net_ads_setspn_add,
3411                         NET_TRANSPORT_ADS,
3412                         N_("Add Service Principal Names (SPN)"),
3413                         N_("net ads setspn add machine spn\n"
3414                            "    Add Service Principal Names (SPN)")
3415                 },
3416                 {
3417                         "delete",
3418                         net_ads_setspn_delete,
3419                         NET_TRANSPORT_ADS,
3420                         N_("Delete Service Principal Names (SPN)"),
3421                         N_("net ads setspn delete machine spn\n"
3422                            "    Delete Service Principal Names (SPN)")
3423                 },
3424                 {NULL, NULL, 0, NULL, NULL}
3425         };
3426
3427         return net_run_function(c, argc, argv, "net ads setspn", func);
3428 }
3429
3430 static int net_ads_enctype_lookup_account(struct net_context *c,
3431                                           ADS_STRUCT *ads,
3432                                           const char *account,
3433                                           LDAPMessage **res,
3434                                           const char **enctype_str)
3435 {
3436         const char *filter;
3437         const char *attrs[] = {
3438                 "msDS-SupportedEncryptionTypes",
3439                 NULL
3440         };
3441         int count;
3442         int ret = -1;
3443         ADS_STATUS status;
3444
3445         filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3446                                  account);
3447         if (filter == NULL) {
3448                 goto done;
3449         }
3450
3451         status = ads_search(ads, res, filter, attrs);
3452         if (!ADS_ERR_OK(status)) {
3453                 d_printf(_("no account found with filter: %s\n"), filter);
3454                 goto done;
3455         }
3456
3457         count = ads_count_replies(ads, *res);
3458         switch (count) {
3459         case 1:
3460                 break;
3461         case 0:
3462                 d_printf(_("no account found with filter: %s\n"), filter);
3463                 goto done;
3464         default:
3465                 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3466                 goto done;
3467         }
3468
3469         if (enctype_str) {
3470                 *enctype_str = ads_pull_string(ads, c, *res,
3471                                                "msDS-SupportedEncryptionTypes");
3472                 if (*enctype_str == NULL) {
3473                         d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3474                         goto done;
3475                 }
3476         }
3477
3478         ret = 0;
3479  done:
3480         return ret;
3481 }
3482
3483 static void net_ads_enctype_dump_enctypes(const char *username,
3484                                           const char *enctype_str)
3485 {
3486         int enctypes = atoi(enctype_str);
3487
3488         d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3489                 username, enctypes, enctypes);
3490
3491         printf("[%s] 0x%08x DES-CBC-CRC\n",
3492                 enctypes & ENC_CRC32 ? "X" : " ",
3493                 ENC_CRC32);
3494         printf("[%s] 0x%08x DES-CBC-MD5\n",
3495                 enctypes & ENC_RSA_MD5 ? "X" : " ",
3496                 ENC_RSA_MD5);
3497         printf("[%s] 0x%08x RC4-HMAC\n",
3498                 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3499                 ENC_RC4_HMAC_MD5);
3500         printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3501                 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3502                 ENC_HMAC_SHA1_96_AES128);
3503         printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3504                 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3505                 ENC_HMAC_SHA1_96_AES256);
3506 }
3507
3508 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3509 {
3510         int ret = -1;
3511         ADS_STATUS status;
3512         ADS_STRUCT *ads = NULL;
3513         LDAPMessage *res = NULL;
3514         const char *str = NULL;
3515
3516         if (c->display_usage || (argc < 1)) {
3517                 d_printf(  "%s\n"
3518                            "net ads enctypes list\n"
3519                            "    %s\n",
3520                          _("Usage:"),
3521                          _("List supported enctypes"));
3522                 return 0;
3523         }
3524
3525         status = ads_startup(c, false, &ads);
3526         if (!ADS_ERR_OK(status)) {
3527                 printf("startup failed\n");
3528                 return ret;
3529         }
3530
3531         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3532         if (ret) {
3533                 goto done;
3534         }
3535
3536         net_ads_enctype_dump_enctypes(argv[0], str);
3537
3538         ret = 0;
3539  done:
3540         ads_msgfree(ads, res);
3541         ads_destroy(&ads);
3542
3543         return ret;
3544 }
3545
3546 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3547 {
3548         int ret = -1;
3549         ADS_STATUS status;
3550         ADS_STRUCT *ads;
3551         LDAPMessage *res = NULL;
3552         const char *etype_list_str;
3553         const char *dn;
3554         ADS_MODLIST mods;
3555         uint32_t etype_list;
3556         const char *str;
3557
3558         if (c->display_usage || argc < 1) {
3559                 d_printf(  "%s\n"
3560                            "net ads enctypes set <sAMAccountName> [enctypes]\n"
3561                            "    %s\n",
3562                          _("Usage:"),
3563                          _("Set supported enctypes"));
3564                 return 0;
3565         }
3566
3567         status = ads_startup(c, false, &ads);
3568         if (!ADS_ERR_OK(status)) {
3569                 printf("startup failed\n");
3570                 return ret;
3571         }
3572
3573         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3574         if (ret) {
3575                 goto done;
3576         }
3577
3578         dn = ads_get_dn(ads, c, res);
3579         if (dn == NULL) {
3580                 goto done;
3581         }
3582
3583         etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3584 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3585         etype_list |= ENC_HMAC_SHA1_96_AES128;
3586 #endif
3587 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3588         etype_list |= ENC_HMAC_SHA1_96_AES256;
3589 #endif
3590
3591         if (argv[1] != NULL) {
3592                 sscanf(argv[1], "%i", &etype_list);
3593         }
3594
3595         etype_list_str = talloc_asprintf(c, "%d", etype_list);
3596         if (!etype_list_str) {
3597                 goto done;
3598         }
3599
3600         mods = ads_init_mods(c);
3601         if (!mods) {
3602                 goto done;
3603         }
3604
3605         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3606                              etype_list_str);
3607         if (!ADS_ERR_OK(status)) {
3608                 goto done;
3609         }
3610
3611         status = ads_gen_mod(ads, dn, mods);
3612         if (!ADS_ERR_OK(status)) {
3613                 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3614                         ads_errstr(status));
3615                 goto done;
3616         }
3617
3618         ads_msgfree(ads, res);
3619
3620         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3621         if (ret) {
3622                 goto done;
3623         }
3624
3625         net_ads_enctype_dump_enctypes(argv[0], str);
3626
3627         ret = 0;
3628  done:
3629         ads_msgfree(ads, res);
3630         ads_destroy(&ads);
3631
3632         return ret;
3633 }
3634
3635 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3636 {
3637         int ret = -1;
3638         ADS_STATUS status;
3639         ADS_STRUCT *ads;
3640         LDAPMessage *res = NULL;
3641         const char *dn;
3642         ADS_MODLIST mods;
3643
3644         if (c->display_usage || argc < 1) {
3645                 d_printf(  "%s\n"
3646                            "net ads enctypes delete <sAMAccountName>\n"
3647                            "    %s\n",
3648                          _("Usage:"),
3649                          _("Delete supported enctypes"));
3650                 return 0;
3651         }
3652
3653         status = ads_startup(c, false, &ads);
3654         if (!ADS_ERR_OK(status)) {
3655                 printf("startup failed\n");
3656                 return ret;
3657         }
3658
3659         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3660         if (ret) {
3661                 goto done;
3662         }
3663
3664         dn = ads_get_dn(ads, c, res);
3665         if (dn == NULL) {
3666                 goto done;
3667         }
3668
3669         mods = ads_init_mods(c);
3670         if (!mods) {
3671                 goto done;
3672         }
3673
3674         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3675         if (!ADS_ERR_OK(status)) {
3676                 goto done;
3677         }
3678
3679         status = ads_gen_mod(ads, dn, mods);
3680         if (!ADS_ERR_OK(status)) {
3681                 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3682                         ads_errstr(status));
3683                 goto done;
3684         }
3685
3686         ret = 0;
3687
3688  done:
3689         ads_msgfree(ads, res);
3690         ads_destroy(&ads);
3691         return ret;
3692 }
3693
3694 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3695 {
3696         struct functable func[] = {
3697                 {
3698                         "list",
3699                         net_ads_enctypes_list,
3700                         NET_TRANSPORT_ADS,
3701                         N_("List the supported encryption types"),
3702                         N_("net ads enctypes list\n"
3703                            "    List the supported encryption types")
3704                 },
3705                 {
3706                         "set",
3707                         net_ads_enctypes_set,
3708                         NET_TRANSPORT_ADS,
3709                         N_("Set the supported encryption types"),
3710                         N_("net ads enctypes set\n"
3711                            "    Set the supported encryption types")
3712                 },
3713                 {
3714                         "delete",
3715                         net_ads_enctypes_delete,
3716                         NET_TRANSPORT_ADS,
3717                         N_("Delete the supported encryption types"),
3718                         N_("net ads enctypes delete\n"
3719                            "    Delete the supported encryption types")
3720                 },
3721
3722                 {NULL, NULL, 0, NULL, NULL}
3723         };
3724
3725         return net_run_function(c, argc, argv, "net ads enctypes", func);
3726 }
3727
3728
3729 int net_ads(struct net_context *c, int argc, const char **argv)
3730 {
3731         struct functable func[] = {
3732                 {
3733                         "info",
3734                         net_ads_info,
3735                         NET_TRANSPORT_ADS,
3736                         N_("Display details on remote ADS server"),
3737                         N_("net ads info\n"
3738                            "    Display details on remote ADS server")
3739                 },
3740                 {
3741                         "join",
3742                         net_ads_join,
3743                         NET_TRANSPORT_ADS,
3744                         N_("Join the local machine to ADS realm"),
3745                         N_("net ads join\n"
3746                            "    Join the local machine to ADS realm")
3747                 },
3748                 {
3749                         "testjoin",
3750                         net_ads_testjoin,
3751                         NET_TRANSPORT_ADS,
3752                         N_("Validate machine account"),
3753                         N_("net ads testjoin\n"
3754                            "    Validate machine account")
3755                 },
3756                 {
3757                         "leave",
3758                         net_ads_leave,
3759                         NET_TRANSPORT_ADS,
3760                         N_("Remove the local machine from ADS"),
3761                         N_("net ads leave\n"
3762                            "    Remove the local machine from ADS")
3763                 },
3764                 {
3765                         "status",
3766                         net_ads_status,
3767                         NET_TRANSPORT_ADS,
3768                         N_("Display machine account details"),
3769                         N_("net ads status\n"
3770                            "    Display machine account details")
3771                 },
3772                 {
3773                         "user",
3774                         net_ads_user,
3775                         NET_TRANSPORT_ADS,
3776                         N_("List/modify users"),
3777                         N_("net ads user\n"
3778                            "    List/modify users")
3779                 },
3780                 {
3781                         "group",
3782                         net_ads_group,
3783                         NET_TRANSPORT_ADS,
3784                         N_("List/modify groups"),
3785                         N_("net ads group\n"
3786                            "    List/modify groups")
3787                 },
3788                 {
3789                         "dns",
3790                         net_ads_dns,
3791                         NET_TRANSPORT_ADS,
3792                         N_("Issue dynamic DNS update"),
3793                         N_("net ads dns\n"
3794                            "    Issue dynamic DNS update")
3795                 },
3796                 {
3797                         "password",
3798                         net_ads_password,
3799                         NET_TRANSPORT_ADS,
3800                         N_("Change user passwords"),
3801                         N_("net ads password\n"
3802                            "    Change user passwords")
3803                 },
3804                 {
3805                         "changetrustpw",
3806                         net_ads_changetrustpw,
3807                         NET_TRANSPORT_ADS,
3808                         N_("Change trust account password"),
3809                         N_("net ads changetrustpw\n"
3810                            "    Change trust account password")
3811                 },
3812                 {
3813                         "printer",
3814                         net_ads_printer,
3815                         NET_TRANSPORT_ADS,
3816                         N_("List/modify printer entries"),
3817                         N_("net ads printer\n"
3818                            "    List/modify printer entries")
3819                 },
3820                 {
3821                         "search",
3822                         net_ads_search,
3823                         NET_TRANSPORT_ADS,
3824                         N_("Issue LDAP search using filter"),
3825                         N_("net ads search\n"
3826                            "    Issue LDAP search using filter")
3827                 },
3828                 {
3829                         "dn",
3830                         net_ads_dn,
3831                         NET_TRANSPORT_ADS,
3832                         N_("Issue LDAP search by DN"),
3833                         N_("net ads dn\n"
3834                            "    Issue LDAP search by DN")
3835                 },
3836                 {
3837                         "sid",
3838                         net_ads_sid,
3839                         NET_TRANSPORT_ADS,
3840                         N_("Issue LDAP search by SID"),
3841                         N_("net ads sid\n"
3842                            "    Issue LDAP search by SID")
3843                 },
3844                 {
3845                         "workgroup",
3846                         net_ads_workgroup,
3847                         NET_TRANSPORT_ADS,
3848                         N_("Display workgroup name"),
3849                         N_("net ads workgroup\n"
3850                            "    Display the workgroup name")
3851                 },
3852                 {
3853                         "lookup",
3854                         net_ads_lookup,
3855                         NET_TRANSPORT_ADS,
3856                         N_("Perform CLDAP query on DC"),
3857                         N_("net ads lookup\n"
3858                            "    Find the ADS DC using CLDAP lookups")
3859                 },
3860                 {
3861                         "keytab",
3862                         net_ads_keytab,
3863                         NET_TRANSPORT_ADS,
3864                         N_("Manage local keytab file"),
3865                         N_("net ads keytab\n"
3866                            "    Manage local keytab file")
3867                 },
3868                 {
3869                         "setspn",
3870                         net_ads_setspn,
3871                         NET_TRANSPORT_ADS,
3872                         N_("Manage Service Principal Names (SPN)s"),
3873                         N_("net ads spnset\n"
3874                            "    Manage Service Principal Names (SPN)s")
3875                 },
3876                 {
3877                         "gpo",
3878                         net_ads_gpo,
3879                         NET_TRANSPORT_ADS,
3880                         N_("Manage group policy objects"),
3881                         N_("net ads gpo\n"
3882                            "    Manage group policy objects")
3883                 },
3884                 {
3885                         "kerberos",
3886                         net_ads_kerberos,
3887                         NET_TRANSPORT_ADS,
3888                         N_("Manage kerberos keytab"),
3889                         N_("net ads kerberos\n"
3890                            "    Manage kerberos keytab")
3891                 },
3892                 {
3893                         "enctypes",
3894                         net_ads_enctypes,
3895                         NET_TRANSPORT_ADS,
3896                         N_("List/modify supported encryption types"),
3897                         N_("net ads enctypes\n"
3898                            "    List/modify enctypes")
3899                 },
3900                 {NULL, NULL, 0, NULL, NULL}
3901         };
3902
3903         return net_run_function(c, argc, argv, "net ads", func);
3904 }
3905
3906 #else
3907
3908 static int net_ads_noads(void)
3909 {
3910         d_fprintf(stderr, _("ADS support not compiled in\n"));
3911         return -1;
3912 }
3913
3914 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3915 {
3916         return net_ads_noads();
3917 }
3918
3919 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3920 {
3921         return net_ads_noads();
3922 }
3923
3924 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3925 {
3926         return net_ads_noads();
3927 }
3928
3929 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3930 {
3931         return net_ads_noads();
3932 }
3933
3934 int net_ads_join(struct net_context *c, int argc, const char **argv)
3935 {
3936         return net_ads_noads();
3937 }
3938
3939 int net_ads_user(struct net_context *c, int argc, const char **argv)
3940 {
3941         return net_ads_noads();
3942 }
3943
3944 int net_ads_group(struct net_context *c, int argc, const char **argv)
3945 {
3946         return net_ads_noads();
3947 }
3948
3949 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3950 {
3951         return net_ads_noads();
3952 }
3953
3954 /* this one shouldn't display a message */
3955 int net_ads_check(struct net_context *c)
3956 {
3957         return -1;
3958 }
3959
3960 int net_ads_check_our_domain(struct net_context *c)
3961 {
3962         return -1;
3963 }
3964
3965 int net_ads(struct net_context *c, int argc, const char **argv)
3966 {
3967         return net_ads_noads();
3968 }
3969
3970 #endif  /* HAVE_ADS */