s3:net: Refactor net_ads_user(), allocate a talloc context
[gd/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         ADS_STRUCT *ads;
1203         ADS_STATUS status;
1204         LDAPMessage *res=NULL;
1205         int rc = -1;
1206         char *ou_str = NULL;
1207
1208         if (argc < 1 || c->display_usage) {
1209                 return net_ads_group_usage(c, argc, argv);
1210         }
1211
1212         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1213                 return -1;
1214         }
1215
1216         status = ads_find_user_acct(ads, &res, argv[0]);
1217
1218         if (!ADS_ERR_OK(status)) {
1219                 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1220                 goto done;
1221         }
1222
1223         if (ads_count_replies(ads, res)) {
1224                 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1225                 goto done;
1226         }
1227
1228         if (c->opt_container) {
1229                 ou_str = SMB_STRDUP(c->opt_container);
1230         } else {
1231                 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1232         }
1233
1234         status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1235
1236         if (ADS_ERR_OK(status)) {
1237                 d_printf(_("Group %s added\n"), argv[0]);
1238                 rc = 0;
1239         } else {
1240                 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1241                          ads_errstr(status));
1242         }
1243
1244  done:
1245         if (res)
1246                 ads_msgfree(ads, res);
1247         ads_destroy(&ads);
1248         SAFE_FREE(ou_str);
1249         return rc;
1250 }
1251
1252 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1253 {
1254         ADS_STRUCT *ads;
1255         ADS_STATUS rc;
1256         LDAPMessage *res = NULL;
1257         char *groupdn;
1258
1259         if (argc < 1 || c->display_usage) {
1260                 return net_ads_group_usage(c, argc, argv);
1261         }
1262
1263         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1264                 return -1;
1265         }
1266
1267         rc = ads_find_user_acct(ads, &res, argv[0]);
1268         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1269                 d_printf(_("Group %s does not exist.\n"), argv[0]);
1270                 ads_msgfree(ads, res);
1271                 ads_destroy(&ads);
1272                 return -1;
1273         }
1274         groupdn = ads_get_dn(ads, talloc_tos(), res);
1275         ads_msgfree(ads, res);
1276         rc = ads_del_dn(ads, groupdn);
1277         TALLOC_FREE(groupdn);
1278         if (ADS_ERR_OK(rc)) {
1279                 d_printf(_("Group %s deleted\n"), argv[0]);
1280                 ads_destroy(&ads);
1281                 return 0;
1282         }
1283         d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1284                  ads_errstr(rc));
1285         ads_destroy(&ads);
1286         return -1;
1287 }
1288
1289 int net_ads_group(struct net_context *c, int argc, const char **argv)
1290 {
1291         struct functable func[] = {
1292                 {
1293                         "add",
1294                         ads_group_add,
1295                         NET_TRANSPORT_ADS,
1296                         N_("Add an AD group"),
1297                         N_("net ads group add\n"
1298                            "    Add an AD group")
1299                 },
1300                 {
1301                         "delete",
1302                         ads_group_delete,
1303                         NET_TRANSPORT_ADS,
1304                         N_("Delete an AD group"),
1305                         N_("net ads group delete\n"
1306                            "    Delete an AD group")
1307                 },
1308                 {NULL, NULL, 0, NULL, NULL}
1309         };
1310         ADS_STRUCT *ads;
1311         ADS_STATUS rc;
1312         const char *shortattrs[] = {"sAMAccountName", NULL};
1313         const char *longattrs[] = {"sAMAccountName", "description", NULL};
1314         char *disp_fields[2] = {NULL, NULL};
1315
1316         if (argc == 0) {
1317                 if (c->display_usage) {
1318                         d_printf(  "%s\n"
1319                                    "net ads group\n"
1320                                    "    %s\n",
1321                                  _("Usage:"),
1322                                  _("List AD groups"));
1323                         net_display_usage_from_functable(func);
1324                         return 0;
1325                 }
1326
1327                 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1328                         return -1;
1329                 }
1330
1331                 if (c->opt_long_list_entries)
1332                         d_printf(_("\nGroup name            Comment"
1333                                    "\n-----------------------------\n"));
1334                 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1335                                           LDAP_SCOPE_SUBTREE,
1336                                           "(objectCategory=group)",
1337                                           c->opt_long_list_entries ? longattrs :
1338                                           shortattrs, usergrp_display,
1339                                           disp_fields);
1340
1341                 ads_destroy(&ads);
1342                 return ADS_ERR_OK(rc) ? 0 : -1;
1343         }
1344         return net_run_function(c, argc, argv, "net ads group", func);
1345 }
1346
1347 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1348 {
1349         ADS_STRUCT *ads;
1350         ADS_STATUS rc;
1351         LDAPMessage *res;
1352
1353         if (c->display_usage) {
1354                 d_printf(  "%s\n"
1355                            "net ads status\n"
1356                            "    %s\n",
1357                          _("Usage:"),
1358                          _("Display machine account details"));
1359                 return 0;
1360         }
1361
1362         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1363                 return -1;
1364         }
1365
1366         rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1367         if (!ADS_ERR_OK(rc)) {
1368                 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1369                 ads_destroy(&ads);
1370                 return -1;
1371         }
1372
1373         if (ads_count_replies(ads, res) == 0) {
1374                 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1375                 ads_destroy(&ads);
1376                 return -1;
1377         }
1378
1379         ads_dump(ads, res);
1380         ads_destroy(&ads);
1381         return 0;
1382 }
1383
1384 /*******************************************************************
1385  Leave an AD domain.  Windows XP disables the machine account.
1386  We'll try the same.  The old code would do an LDAP delete.
1387  That only worked using the machine creds because added the machine
1388  with full control to the computer object's ACL.
1389 *******************************************************************/
1390
1391 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1392 {
1393         TALLOC_CTX *ctx;
1394         struct libnet_UnjoinCtx *r = NULL;
1395         WERROR werr;
1396
1397         if (c->display_usage) {
1398                 d_printf(  "%s\n"
1399                            "net ads leave [--keep-account]\n"
1400                            "    %s\n",
1401                          _("Usage:"),
1402                          _("Leave an AD domain"));
1403                 return 0;
1404         }
1405
1406         if (!*lp_realm()) {
1407                 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1408                 return -1;
1409         }
1410
1411         if (!(ctx = talloc_init("net_ads_leave"))) {
1412                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1413                 return -1;
1414         }
1415
1416         if (!c->opt_kerberos) {
1417                 use_in_memory_ccache();
1418         }
1419
1420         if (!c->msg_ctx) {
1421                 d_fprintf(stderr, _("Could not initialise message context. "
1422                         "Try running as root\n"));
1423                 return -1;
1424         }
1425
1426         werr = libnet_init_UnjoinCtx(ctx, &r);
1427         if (!W_ERROR_IS_OK(werr)) {
1428                 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1429                 return -1;
1430         }
1431
1432         r->in.debug             = true;
1433         r->in.use_kerberos      = c->opt_kerberos;
1434         r->in.dc_name           = c->opt_host;
1435         r->in.domain_name       = lp_realm();
1436         r->in.admin_account     = c->opt_user_name;
1437         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1438         r->in.modify_config     = lp_config_backend_is_registry();
1439
1440         /* Try to delete it, but if that fails, disable it.  The
1441            WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1442         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1443                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1444         if (c->opt_keep_account) {
1445                 r->in.delete_machine_account = false;
1446         } else {
1447                 r->in.delete_machine_account = true;
1448         }
1449
1450         r->in.msg_ctx           = c->msg_ctx;
1451
1452         werr = libnet_Unjoin(ctx, r);
1453         if (!W_ERROR_IS_OK(werr)) {
1454                 d_printf(_("Failed to leave domain: %s\n"),
1455                          r->out.error_string ? r->out.error_string :
1456                          get_friendly_werror_msg(werr));
1457                 goto done;
1458         }
1459
1460         if (r->out.deleted_machine_account) {
1461                 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1462                         r->in.machine_name, r->out.dns_domain_name);
1463                 goto done;
1464         }
1465
1466         /* We couldn't delete it - see if the disable succeeded. */
1467         if (r->out.disabled_machine_account) {
1468                 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1469                         r->in.machine_name, r->out.dns_domain_name);
1470                 werr = WERR_OK;
1471                 goto done;
1472         }
1473
1474         /* Based on what we requested, we shouldn't get here, but if
1475            we did, it means the secrets were removed, and therefore
1476            we have left the domain */
1477         d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1478                   r->in.machine_name, r->out.dns_domain_name);
1479
1480  done:
1481         TALLOC_FREE(r);
1482         TALLOC_FREE(ctx);
1483
1484         if (W_ERROR_IS_OK(werr)) {
1485                 return 0;
1486         }
1487
1488         return -1;
1489 }
1490
1491 static NTSTATUS net_ads_join_ok(struct net_context *c)
1492 {
1493         ADS_STRUCT *ads = NULL;
1494         ADS_STATUS status;
1495         fstring dc_name;
1496         struct sockaddr_storage dcip;
1497
1498         if (!secrets_init()) {
1499                 DEBUG(1,("Failed to initialise secrets database\n"));
1500                 return NT_STATUS_ACCESS_DENIED;
1501         }
1502
1503         net_use_krb_machine_account(c);
1504
1505         get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1506
1507         status = ads_startup(c, true, &ads);
1508         if (!ADS_ERR_OK(status)) {
1509                 return ads_ntstatus(status);
1510         }
1511
1512         ads_destroy(&ads);
1513         return NT_STATUS_OK;
1514 }
1515
1516 /*
1517   check that an existing join is OK
1518  */
1519 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1520 {
1521         NTSTATUS status;
1522         use_in_memory_ccache();
1523
1524         if (c->display_usage) {
1525                 d_printf(  "%s\n"
1526                            "net ads testjoin\n"
1527                            "    %s\n",
1528                          _("Usage:"),
1529                          _("Test if the existing join is ok"));
1530                 return 0;
1531         }
1532
1533         /* Display success or failure */
1534         status = net_ads_join_ok(c);
1535         if (!NT_STATUS_IS_OK(status)) {
1536                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1537                         get_friendly_nt_error_msg(status));
1538                 return -1;
1539         }
1540
1541         printf(_("Join is OK\n"));
1542         return 0;
1543 }
1544
1545 /*******************************************************************
1546   Simple config checks before beginning the join
1547  ********************************************************************/
1548
1549 static WERROR check_ads_config( void )
1550 {
1551         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1552                 d_printf(_("Host is not configured as a member server.\n"));
1553                 return WERR_INVALID_DOMAIN_ROLE;
1554         }
1555
1556         if (strlen(lp_netbios_name()) > 15) {
1557                 d_printf(_("Our netbios name can be at most 15 chars long, "
1558                            "\"%s\" is %u chars long\n"), lp_netbios_name(),
1559                          (unsigned int)strlen(lp_netbios_name()));
1560                 return WERR_INVALID_COMPUTERNAME;
1561         }
1562
1563         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1564                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1565                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1566                 return WERR_INVALID_PARAMETER;
1567         }
1568
1569         return WERR_OK;
1570 }
1571
1572 /*******************************************************************
1573  ********************************************************************/
1574
1575 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1576 {
1577         d_printf(_("net ads join [--no-dns-updates] [options]\n"
1578                    "Valid options:\n"));
1579         d_printf(_("   dnshostname=FQDN      Set the dnsHostName attribute during the join.\n"
1580                    "                         The default is in the form netbiosname.dnsdomain\n"));
1581         d_printf(_("   createupn[=UPN]       Set the userPrincipalName attribute during the join.\n"
1582                    "                         The default UPN is in the form host/netbiosname@REALM.\n"));
1583         d_printf(_("   createcomputer=OU     Precreate the computer account in a specific OU.\n"
1584                    "                         The OU string read from top to bottom without RDNs\n"
1585                    "                         and delimited by a '/'.\n"
1586                    "                         E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1587                    "                         NB: A backslash '\\' is used as escape at multiple\n"
1588                    "                             levels and may need to be doubled or even\n"
1589                    "                             quadrupled. It is not used as a separator.\n"));
1590         d_printf(_("   machinepass=PASS      Set the machine password to a specific value during\n"
1591                    "                         the join. The default password is random.\n"));
1592         d_printf(_("   osName=string         Set the operatingSystem attribute during the join.\n"));
1593         d_printf(_("   osVer=string          Set the operatingSystemVersion attribute during join.\n"
1594                    "                         NB: osName and osVer must be specified together for\n"
1595                    "                             either to take effect. The operatingSystemService\n"
1596                    "                             attribute is then also set along with the two\n"
1597                    "                             other attributes.\n"));
1598         d_printf(_("   osServicePack=string  Set the operatingSystemServicePack attribute\n"
1599                    "                         during the join.\n"
1600                    "                         NB: If not specified then by default the samba\n"
1601                    "                             version string is used instead.\n"));
1602         return -1;
1603 }
1604
1605
1606 int net_ads_join(struct net_context *c, int argc, const char **argv)
1607 {
1608         TALLOC_CTX *ctx = NULL;
1609         struct libnet_JoinCtx *r = NULL;
1610         const char *domain = lp_realm();
1611         WERROR werr = WERR_NERR_SETUPNOTJOINED;
1612         bool createupn = false;
1613         const char *dnshostname = NULL;
1614         const char *machineupn = NULL;
1615         const char *machine_password = NULL;
1616         const char *create_in_ou = NULL;
1617         int i;
1618         const char *os_name = NULL;
1619         const char *os_version = NULL;
1620         const char *os_servicepack = NULL;
1621         bool modify_config = lp_config_backend_is_registry();
1622         enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1623
1624         if (c->display_usage)
1625                 return net_ads_join_usage(c, argc, argv);
1626
1627         if (!modify_config) {
1628
1629                 werr = check_ads_config();
1630                 if (!W_ERROR_IS_OK(werr)) {
1631                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1632                         goto fail;
1633                 }
1634         }
1635
1636         if (!(ctx = talloc_init("net_ads_join"))) {
1637                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1638                 werr = WERR_NOT_ENOUGH_MEMORY;
1639                 goto fail;
1640         }
1641
1642         if (!c->opt_kerberos) {
1643                 use_in_memory_ccache();
1644         }
1645
1646         werr = libnet_init_JoinCtx(ctx, &r);
1647         if (!W_ERROR_IS_OK(werr)) {
1648                 goto fail;
1649         }
1650
1651         /* process additional command line args */
1652
1653         for ( i=0; i<argc; i++ ) {
1654                 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1655                         dnshostname = get_string_param(argv[i]);
1656                 }
1657                 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1658                         createupn = true;
1659                         machineupn = get_string_param(argv[i]);
1660                 }
1661                 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1662                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1663                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1664                                 werr = WERR_INVALID_PARAMETER;
1665                                 goto fail;
1666                         }
1667                 }
1668                 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1669                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1670                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1671                                 werr = WERR_INVALID_PARAMETER;
1672                                 goto fail;
1673                         }
1674                 }
1675                 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1676                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1677                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1678                                 werr = WERR_INVALID_PARAMETER;
1679                                 goto fail;
1680                         }
1681                 }
1682                 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1683                         if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1684                                 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1685                                 werr = WERR_INVALID_PARAMETER;
1686                                 goto fail;
1687                         }
1688                 }
1689                 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1690                         if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1691                                 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1692                                 werr = WERR_INVALID_PARAMETER;
1693                                 goto fail;
1694                         }
1695                 }
1696                 else {
1697                         domain = argv[i];
1698                         if (strchr(domain, '.') == NULL) {
1699                                 domain_name_type = JoinDomNameTypeUnknown;
1700                         } else {
1701                                 domain_name_type = JoinDomNameTypeDNS;
1702                         }
1703                 }
1704         }
1705
1706         if (!*domain) {
1707                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1708                 werr = WERR_INVALID_PARAMETER;
1709                 goto fail;
1710         }
1711
1712         if (!c->msg_ctx) {
1713                 d_fprintf(stderr, _("Could not initialise message context. "
1714                         "Try running as root\n"));
1715                 werr = WERR_ACCESS_DENIED;
1716                 goto fail;
1717         }
1718
1719         /* Do the domain join here */
1720
1721         r->in.domain_name       = domain;
1722         r->in.domain_name_type  = domain_name_type;
1723         r->in.create_upn        = createupn;
1724         r->in.upn               = machineupn;
1725         r->in.dnshostname       = dnshostname;
1726         r->in.account_ou        = create_in_ou;
1727         r->in.os_name           = os_name;
1728         r->in.os_version        = os_version;
1729         r->in.os_servicepack    = os_servicepack;
1730         r->in.dc_name           = c->opt_host;
1731         r->in.admin_account     = c->opt_user_name;
1732         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1733         r->in.machine_password  = machine_password;
1734         r->in.debug             = true;
1735         r->in.use_kerberos      = c->opt_kerberos;
1736         r->in.modify_config     = modify_config;
1737         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1738                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1739                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1740         r->in.msg_ctx           = c->msg_ctx;
1741
1742         werr = libnet_Join(ctx, r);
1743         if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1744             strequal(domain, lp_realm())) {
1745                 r->in.domain_name = lp_workgroup();
1746                 r->in.domain_name_type = JoinDomNameTypeNBT;
1747                 werr = libnet_Join(ctx, r);
1748         }
1749         if (!W_ERROR_IS_OK(werr)) {
1750                 goto fail;
1751         }
1752
1753         /* Check the short name of the domain */
1754
1755         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1756                 d_printf(_("The workgroup in %s does not match the short\n"
1757                            "domain name obtained from the server.\n"
1758                            "Using the name [%s] from the server.\n"
1759                            "You should set \"workgroup = %s\" in %s.\n"),
1760                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1761                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1762         }
1763
1764         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1765
1766         if (r->out.dns_domain_name) {
1767                 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1768                         r->out.dns_domain_name);
1769         } else {
1770                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1771                         r->out.netbios_domain_name);
1772         }
1773
1774         /* print out informative error string in case there is one */
1775         if (r->out.error_string != NULL) {
1776                 d_printf("%s\n", r->out.error_string);
1777         }
1778
1779         /*
1780          * We try doing the dns update (if it was compiled in
1781          * and if it was not disabled on the command line).
1782          * If the dns update fails, we still consider the join
1783          * operation as succeeded if we came this far.
1784          */
1785         if (!c->opt_no_dns_updates) {
1786                 net_ads_join_dns_updates(c, ctx, r);
1787         }
1788
1789         TALLOC_FREE(r);
1790         TALLOC_FREE( ctx );
1791
1792         return 0;
1793
1794 fail:
1795         /* issue an overall failure message at the end. */
1796         d_printf(_("Failed to join domain: %s\n"),
1797                 r && r->out.error_string ? r->out.error_string :
1798                 get_friendly_werror_msg(werr));
1799         TALLOC_FREE( ctx );
1800
1801         return -1;
1802 }
1803
1804 /*******************************************************************
1805  ********************************************************************/
1806
1807 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1808 {
1809 #if defined(HAVE_KRB5)
1810         ADS_STRUCT *ads;
1811         ADS_STATUS status;
1812         NTSTATUS ntstatus;
1813         TALLOC_CTX *ctx;
1814         const char *hostname = NULL;
1815         const char **addrs_list = NULL;
1816         struct sockaddr_storage *addrs = NULL;
1817         int num_addrs = 0;
1818         int count;
1819
1820 #ifdef DEVELOPER
1821         talloc_enable_leak_report();
1822 #endif
1823
1824         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1825                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1826                                     "detection of addresses in a clustered "
1827                                     "setup.\n"));
1828                 c->display_usage = true;
1829         }
1830
1831         if (c->display_usage) {
1832                 d_printf(  "%s\n"
1833                            "net ads dns register [hostname [IP [IP...]]]\n"
1834                            "    %s\n",
1835                          _("Usage:"),
1836                          _("Register hostname with DNS\n"));
1837                 return -1;
1838         }
1839
1840         if (!(ctx = talloc_init("net_ads_dns"))) {
1841                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1842                 return -1;
1843         }
1844
1845         if (argc >= 1) {
1846                 hostname = argv[0];
1847         }
1848
1849         if (argc > 1) {
1850                 num_addrs = argc - 1;
1851                 addrs_list = &argv[1];
1852         } else if (lp_clustering()) {
1853                 addrs_list = lp_cluster_addresses();
1854                 num_addrs = str_list_length(addrs_list);
1855         }
1856
1857         if (num_addrs > 0) {
1858                 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1859                 if (addrs == NULL) {
1860                         d_fprintf(stderr, _("Error allocating memory!\n"));
1861                         talloc_free(ctx);
1862                         return -1;
1863                 }
1864         }
1865
1866         for (count = 0; count < num_addrs; count++) {
1867                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1868                         d_fprintf(stderr, "%s '%s'.\n",
1869                                           _("Cannot interpret address"),
1870                                           addrs_list[count]);
1871                         talloc_free(ctx);
1872                         return -1;
1873                 }
1874         }
1875
1876         status = ads_startup(c, true, &ads);
1877         if ( !ADS_ERR_OK(status) ) {
1878                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1879                 TALLOC_FREE(ctx);
1880                 return -1;
1881         }
1882
1883         ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1884         if (!NT_STATUS_IS_OK(ntstatus)) {
1885                 d_fprintf( stderr, _("DNS update failed!\n") );
1886                 ads_destroy( &ads );
1887                 TALLOC_FREE( ctx );
1888                 return -1;
1889         }
1890
1891         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1892
1893         ads_destroy(&ads);
1894         TALLOC_FREE( ctx );
1895
1896         return 0;
1897 #else
1898         d_fprintf(stderr,
1899                   _("DNS update support not enabled at compile time!\n"));
1900         return -1;
1901 #endif
1902 }
1903
1904 static int net_ads_dns_unregister(struct net_context *c,
1905                                   int argc,
1906                                   const char **argv)
1907 {
1908 #if defined(HAVE_KRB5)
1909         ADS_STRUCT *ads;
1910         ADS_STATUS status;
1911         NTSTATUS ntstatus;
1912         TALLOC_CTX *ctx;
1913         const char *hostname = NULL;
1914
1915 #ifdef DEVELOPER
1916         talloc_enable_leak_report();
1917 #endif
1918
1919         if (argc != 1) {
1920                 c->display_usage = true;
1921         }
1922
1923         if (c->display_usage) {
1924                 d_printf(  "%s\n"
1925                            "net ads dns unregister [hostname]\n"
1926                            "    %s\n",
1927                          _("Usage:"),
1928                          _("Remove all IP Address entires for a given\n"
1929                            "    hostname from the Active Directory server.\n"));
1930                 return -1;
1931         }
1932
1933         if (!(ctx = talloc_init("net_ads_dns"))) {
1934                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1935                 return -1;
1936         }
1937
1938         /* Get the hostname for un-registering */
1939         hostname = argv[0];
1940
1941         status = ads_startup(c, true, &ads);
1942         if ( !ADS_ERR_OK(status) ) {
1943                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1944                 TALLOC_FREE(ctx);
1945                 return -1;
1946         }
1947
1948         ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1949         if (!NT_STATUS_IS_OK(ntstatus)) {
1950                 d_fprintf( stderr, _("DNS update failed!\n") );
1951                 ads_destroy( &ads );
1952                 TALLOC_FREE( ctx );
1953                 return -1;
1954         }
1955
1956         d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1957
1958         ads_destroy(&ads);
1959         TALLOC_FREE( ctx );
1960
1961         return 0;
1962 #else
1963         d_fprintf(stderr,
1964                   _("DNS update support not enabled at compile time!\n"));
1965         return -1;
1966 #endif
1967 }
1968
1969
1970 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
1971 {
1972         size_t num_names = 0;
1973         char **hostnames = NULL;
1974         size_t i = 0;
1975         struct samba_sockaddr *addrs = NULL;
1976         NTSTATUS status;
1977
1978         if (argc != 1 || c->display_usage) {
1979                 d_printf(  "%s\n"
1980                            "    %s\n"
1981                            "    %s\n",
1982                          _("Usage:"),
1983                          _("net ads dns async <name>\n"),
1984                          _("  Async look up hostname from the DNS server\n"
1985                            "    hostname\tName to look up\n"));
1986                 return -1;
1987         }
1988
1989         status = ads_dns_lookup_a(talloc_tos(),
1990                                   argv[0],
1991                                   &num_names,
1992                                   &hostnames,
1993                                   &addrs);
1994         if (!NT_STATUS_IS_OK(status)) {
1995                 d_printf("Looking up A record for %s got error %s\n",
1996                          argv[0],
1997                          nt_errstr(status));
1998                 return -1;
1999         }
2000         d_printf("Async A record lookup - got %u names for %s\n",
2001                  (unsigned int)num_names,
2002                  argv[0]);
2003         for (i = 0; i < num_names; i++) {
2004                 char addr_buf[INET6_ADDRSTRLEN];
2005                 print_sockaddr(addr_buf,
2006                                sizeof(addr_buf),
2007                                &addrs[i].u.ss);
2008                 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2009                         (unsigned int)i,
2010                         hostnames[i],
2011                         addr_buf);
2012         }
2013
2014 #if defined(HAVE_IPV6)
2015         status = ads_dns_lookup_aaaa(talloc_tos(),
2016                                      argv[0],
2017                                      &num_names,
2018                                      &hostnames,
2019                                      &addrs);
2020         if (!NT_STATUS_IS_OK(status)) {
2021                 d_printf("Looking up AAAA record for %s got error %s\n",
2022                          argv[0],
2023                          nt_errstr(status));
2024                 return -1;
2025         }
2026         d_printf("Async AAAA record lookup - got %u names for %s\n",
2027                  (unsigned int)num_names,
2028                  argv[0]);
2029         for (i = 0; i < num_names; i++) {
2030                 char addr_buf[INET6_ADDRSTRLEN];
2031                 print_sockaddr(addr_buf,
2032                                sizeof(addr_buf),
2033                                &addrs[i].u.ss);
2034                 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2035                         (unsigned int)i,
2036                         hostnames[i],
2037                         addr_buf);
2038         }
2039 #endif
2040         return 0;
2041 }
2042
2043
2044 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2045 {
2046         struct functable func[] = {
2047                 {
2048                         "register",
2049                         net_ads_dns_register,
2050                         NET_TRANSPORT_ADS,
2051                         N_("Add host dns entry to AD"),
2052                         N_("net ads dns register\n"
2053                            "    Add host dns entry to AD")
2054                 },
2055                 {
2056                         "unregister",
2057                         net_ads_dns_unregister,
2058                         NET_TRANSPORT_ADS,
2059                         N_("Remove host dns entry from AD"),
2060                         N_("net ads dns unregister\n"
2061                            "    Remove host dns entry from AD")
2062                 },
2063                 {
2064                         "async",
2065                         net_ads_dns_async,
2066                         NET_TRANSPORT_ADS,
2067                         N_("Look up host"),
2068                         N_("net ads dns async\n"
2069                            "    Look up host using async DNS")
2070                 },
2071                 {NULL, NULL, 0, NULL, NULL}
2072         };
2073
2074         return net_run_function(c, argc, argv, "net ads dns", func);
2075 }
2076
2077 /*******************************************************************
2078  ********************************************************************/
2079
2080 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2081 {
2082         d_printf(_(
2083 "\nnet ads printer search <printer>"
2084 "\n\tsearch for a printer in the directory\n"
2085 "\nnet ads printer info <printer> <server>"
2086 "\n\tlookup info in directory for printer on server"
2087 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2088 "\nnet ads printer publish <printername>"
2089 "\n\tpublish printer in directory"
2090 "\n\t(note: printer name is required)\n"
2091 "\nnet ads printer remove <printername>"
2092 "\n\tremove printer from directory"
2093 "\n\t(note: printer name is required)\n"));
2094         return -1;
2095 }
2096
2097 /*******************************************************************
2098  ********************************************************************/
2099
2100 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2101 {
2102         ADS_STRUCT *ads;
2103         ADS_STATUS rc;
2104         LDAPMessage *res = NULL;
2105
2106         if (c->display_usage) {
2107                 d_printf(  "%s\n"
2108                            "net ads printer search\n"
2109                            "    %s\n",
2110                          _("Usage:"),
2111                          _("List printers in the AD"));
2112                 return 0;
2113         }
2114
2115         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2116                 return -1;
2117         }
2118
2119         rc = ads_find_printers(ads, &res);
2120
2121         if (!ADS_ERR_OK(rc)) {
2122                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2123                 ads_msgfree(ads, res);
2124                 ads_destroy(&ads);
2125                 return -1;
2126         }
2127
2128         if (ads_count_replies(ads, res) == 0) {
2129                 d_fprintf(stderr, _("No results found\n"));
2130                 ads_msgfree(ads, res);
2131                 ads_destroy(&ads);
2132                 return -1;
2133         }
2134
2135         ads_dump(ads, res);
2136         ads_msgfree(ads, res);
2137         ads_destroy(&ads);
2138         return 0;
2139 }
2140
2141 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2142 {
2143         ADS_STRUCT *ads;
2144         ADS_STATUS rc;
2145         const char *servername, *printername;
2146         LDAPMessage *res = NULL;
2147
2148         if (c->display_usage) {
2149                 d_printf("%s\n%s",
2150                          _("Usage:"),
2151                          _("net ads printer info [printername [servername]]\n"
2152                            "  Display printer info from AD\n"
2153                            "    printername\tPrinter name or wildcard\n"
2154                            "    servername\tName of the print server\n"));
2155                 return 0;
2156         }
2157
2158         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2159                 return -1;
2160         }
2161
2162         if (argc > 0) {
2163                 printername = argv[0];
2164         } else {
2165                 printername = "*";
2166         }
2167
2168         if (argc > 1) {
2169                 servername =  argv[1];
2170         } else {
2171                 servername = lp_netbios_name();
2172         }
2173
2174         rc = ads_find_printer_on_server(ads, &res, printername, servername);
2175
2176         if (!ADS_ERR_OK(rc)) {
2177                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2178                         servername, ads_errstr(rc));
2179                 ads_msgfree(ads, res);
2180                 ads_destroy(&ads);
2181                 return -1;
2182         }
2183
2184         if (ads_count_replies(ads, res) == 0) {
2185                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2186                 ads_msgfree(ads, res);
2187                 ads_destroy(&ads);
2188                 return -1;
2189         }
2190
2191         ads_dump(ads, res);
2192         ads_msgfree(ads, res);
2193         ads_destroy(&ads);
2194
2195         return 0;
2196 }
2197
2198 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2199 {
2200         ADS_STRUCT *ads;
2201         ADS_STATUS rc;
2202         const char *servername, *printername;
2203         struct cli_state *cli = NULL;
2204         struct rpc_pipe_client *pipe_hnd = NULL;
2205         struct sockaddr_storage server_ss;
2206         NTSTATUS nt_status;
2207         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2208         ADS_MODLIST mods = ads_init_mods(mem_ctx);
2209         char *prt_dn, *srv_dn, **srv_cn;
2210         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2211         LDAPMessage *res = NULL;
2212         bool ok;
2213
2214         if (argc < 1 || c->display_usage) {
2215                 d_printf("%s\n%s",
2216                          _("Usage:"),
2217                          _("net ads printer publish <printername> [servername]\n"
2218                            "  Publish printer in AD\n"
2219                            "    printername\tName of the printer\n"
2220                            "    servername\tName of the print server\n"));
2221                 talloc_destroy(mem_ctx);
2222                 return -1;
2223         }
2224
2225         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2226                 talloc_destroy(mem_ctx);
2227                 return -1;
2228         }
2229
2230         printername = argv[0];
2231
2232         if (argc == 2) {
2233                 servername = argv[1];
2234         } else {
2235                 servername = lp_netbios_name();
2236         }
2237
2238         /* Get printer data from SPOOLSS */
2239
2240         ok = resolve_name(servername, &server_ss, 0x20, false);
2241         if (!ok) {
2242                 d_fprintf(stderr, _("Could not find server %s\n"),
2243                           servername);
2244                 ads_destroy(&ads);
2245                 talloc_destroy(mem_ctx);
2246                 return -1;
2247         }
2248
2249         cli_credentials_set_kerberos_state(c->creds,
2250                                            CRED_USE_KERBEROS_REQUIRED,
2251                                            CRED_SPECIFIED);
2252
2253         nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2254                                         &server_ss, 0,
2255                                         "IPC$", "IPC",
2256                                         c->creds,
2257                                         CLI_FULL_CONNECTION_IPC);
2258
2259         if (NT_STATUS_IS_ERR(nt_status)) {
2260                 d_fprintf(stderr, _("Unable to open a connection to %s to "
2261                                     "obtain data for %s\n"),
2262                           servername, printername);
2263                 ads_destroy(&ads);
2264                 talloc_destroy(mem_ctx);
2265                 return -1;
2266         }
2267
2268         /* Publish on AD server */
2269
2270         ads_find_machine_acct(ads, &res, servername);
2271
2272         if (ads_count_replies(ads, res) == 0) {
2273                 d_fprintf(stderr, _("Could not find machine account for server "
2274                                     "%s\n"),
2275                          servername);
2276                 ads_destroy(&ads);
2277                 talloc_destroy(mem_ctx);
2278                 return -1;
2279         }
2280
2281         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2282         srv_cn = ldap_explode_dn(srv_dn, 1);
2283
2284         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2285         printername_escaped = escape_rdn_val_string_alloc(printername);
2286         if (!srv_cn_escaped || !printername_escaped) {
2287                 SAFE_FREE(srv_cn_escaped);
2288                 SAFE_FREE(printername_escaped);
2289                 d_fprintf(stderr, _("Internal error, out of memory!"));
2290                 ads_destroy(&ads);
2291                 talloc_destroy(mem_ctx);
2292                 return -1;
2293         }
2294
2295         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2296                 SAFE_FREE(srv_cn_escaped);
2297                 SAFE_FREE(printername_escaped);
2298                 d_fprintf(stderr, _("Internal error, out of memory!"));
2299                 ads_destroy(&ads);
2300                 talloc_destroy(mem_ctx);
2301                 return -1;
2302         }
2303
2304         SAFE_FREE(srv_cn_escaped);
2305         SAFE_FREE(printername_escaped);
2306
2307         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2308         if (!NT_STATUS_IS_OK(nt_status)) {
2309                 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2310                          servername);
2311                 SAFE_FREE(prt_dn);
2312                 ads_destroy(&ads);
2313                 talloc_destroy(mem_ctx);
2314                 return -1;
2315         }
2316
2317         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2318                                                               printername))) {
2319                 SAFE_FREE(prt_dn);
2320                 ads_destroy(&ads);
2321                 talloc_destroy(mem_ctx);
2322                 return -1;
2323         }
2324
2325         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2326         if (!ADS_ERR_OK(rc)) {
2327                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2328                 SAFE_FREE(prt_dn);
2329                 ads_destroy(&ads);
2330                 talloc_destroy(mem_ctx);
2331                 return -1;
2332         }
2333
2334         d_printf("published printer\n");
2335         SAFE_FREE(prt_dn);
2336         ads_destroy(&ads);
2337         talloc_destroy(mem_ctx);
2338
2339         return 0;
2340 }
2341
2342 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2343 {
2344         ADS_STRUCT *ads;
2345         ADS_STATUS rc;
2346         const char *servername;
2347         char *prt_dn;
2348         LDAPMessage *res = NULL;
2349
2350         if (argc < 1 || c->display_usage) {
2351                 d_printf("%s\n%s",
2352                          _("Usage:"),
2353                          _("net ads printer remove <printername> [servername]\n"
2354                            "  Remove a printer from the AD\n"
2355                            "    printername\tName of the printer\n"
2356                            "    servername\tName of the print server\n"));
2357                 return -1;
2358         }
2359
2360         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2361                 return -1;
2362         }
2363
2364         if (argc > 1) {
2365                 servername = argv[1];
2366         } else {
2367                 servername = lp_netbios_name();
2368         }
2369
2370         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2371
2372         if (!ADS_ERR_OK(rc)) {
2373                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2374                 ads_msgfree(ads, res);
2375                 ads_destroy(&ads);
2376                 return -1;
2377         }
2378
2379         if (ads_count_replies(ads, res) == 0) {
2380                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2381                 ads_msgfree(ads, res);
2382                 ads_destroy(&ads);
2383                 return -1;
2384         }
2385
2386         prt_dn = ads_get_dn(ads, talloc_tos(), res);
2387         ads_msgfree(ads, res);
2388         rc = ads_del_dn(ads, prt_dn);
2389         TALLOC_FREE(prt_dn);
2390
2391         if (!ADS_ERR_OK(rc)) {
2392                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2393                 ads_destroy(&ads);
2394                 return -1;
2395         }
2396
2397         ads_destroy(&ads);
2398         return 0;
2399 }
2400
2401 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2402 {
2403         struct functable func[] = {
2404                 {
2405                         "search",
2406                         net_ads_printer_search,
2407                         NET_TRANSPORT_ADS,
2408                         N_("Search for a printer"),
2409                         N_("net ads printer search\n"
2410                            "    Search for a printer")
2411                 },
2412                 {
2413                         "info",
2414                         net_ads_printer_info,
2415                         NET_TRANSPORT_ADS,
2416                         N_("Display printer information"),
2417                         N_("net ads printer info\n"
2418                            "    Display printer information")
2419                 },
2420                 {
2421                         "publish",
2422                         net_ads_printer_publish,
2423                         NET_TRANSPORT_ADS,
2424                         N_("Publish a printer"),
2425                         N_("net ads printer publish\n"
2426                            "    Publish a printer")
2427                 },
2428                 {
2429                         "remove",
2430                         net_ads_printer_remove,
2431                         NET_TRANSPORT_ADS,
2432                         N_("Delete a printer"),
2433                         N_("net ads printer remove\n"
2434                            "    Delete a printer")
2435                 },
2436                 {NULL, NULL, 0, NULL, NULL}
2437         };
2438
2439         return net_run_function(c, argc, argv, "net ads printer", func);
2440 }
2441
2442
2443 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2444 {
2445         ADS_STRUCT *ads;
2446         const char *auth_principal = cli_credentials_get_username(c->creds);
2447         const char *auth_password = cli_credentials_get_password(c->creds);
2448         const char *realm = NULL;
2449         const char *new_password = NULL;
2450         char *chr, *prompt;
2451         const char *user;
2452         char pwd[256] = {0};
2453         ADS_STATUS ret;
2454
2455         if (c->display_usage) {
2456                 d_printf("%s\n%s",
2457                          _("Usage:"),
2458                          _("net ads password <username>\n"
2459                            "  Change password for user\n"
2460                            "    username\tName of user to change password for\n"));
2461                 return 0;
2462         }
2463
2464         if (auth_principal == NULL || auth_password == NULL) {
2465                 d_fprintf(stderr, _("You must supply an administrator "
2466                                     "username/password\n"));
2467                 return -1;
2468         }
2469
2470         if (argc < 1) {
2471                 d_fprintf(stderr, _("ERROR: You must say which username to "
2472                                     "change password for\n"));
2473                 return -1;
2474         }
2475
2476         user = argv[0];
2477         if (!strchr_m(user, '@')) {
2478                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2479                         return -1;
2480                 }
2481                 user = chr;
2482         }
2483
2484         use_in_memory_ccache();
2485         chr = strchr_m(auth_principal, '@');
2486         if (chr) {
2487                 realm = ++chr;
2488         } else {
2489                 realm = lp_realm();
2490         }
2491
2492         /* use the realm so we can eventually change passwords for users
2493         in realms other than default */
2494         ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2495         if (ads == NULL) {
2496                 return -1;
2497         }
2498
2499         /* we don't actually need a full connect, but it's the easy way to
2500                 fill in the KDC's addresss */
2501         ads_connect(ads);
2502
2503         if (!ads->config.realm) {
2504                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2505                 ads_destroy(&ads);
2506                 return -1;
2507         }
2508
2509         if (argv[1]) {
2510                 new_password = (const char *)argv[1];
2511         } else {
2512                 int rc;
2513
2514                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2515                         return -1;
2516                 }
2517                 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2518                 if (rc < 0) {
2519                         return -1;
2520                 }
2521                 new_password = pwd;
2522                 free(prompt);
2523         }
2524
2525         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2526                                 auth_password, user, new_password, ads->auth.time_offset);
2527         memset(pwd, '\0', sizeof(pwd));
2528         if (!ADS_ERR_OK(ret)) {
2529                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2530                 ads_destroy(&ads);
2531                 return -1;
2532         }
2533
2534         d_printf(_("Password change for %s completed.\n"), user);
2535         ads_destroy(&ads);
2536
2537         return 0;
2538 }
2539
2540 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2541 {
2542         ADS_STRUCT *ads;
2543         char *host_principal;
2544         fstring my_name;
2545         ADS_STATUS ret;
2546
2547         if (c->display_usage) {
2548                 d_printf(  "%s\n"
2549                            "net ads changetrustpw\n"
2550                            "    %s\n",
2551                          _("Usage:"),
2552                          _("Change the machine account's trust password"));
2553                 return 0;
2554         }
2555
2556         if (!secrets_init()) {
2557                 DEBUG(1,("Failed to initialise secrets database\n"));
2558                 return -1;
2559         }
2560
2561         net_use_krb_machine_account(c);
2562
2563         use_in_memory_ccache();
2564
2565         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2566                 return -1;
2567         }
2568
2569         fstrcpy(my_name, lp_netbios_name());
2570         if (!strlower_m(my_name)) {
2571                 ads_destroy(&ads);
2572                 return -1;
2573         }
2574
2575         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2576                 ads_destroy(&ads);
2577                 return -1;
2578         }
2579         d_printf(_("Changing password for principal: %s\n"), host_principal);
2580
2581         ret = ads_change_trust_account_password(ads, host_principal);
2582
2583         if (!ADS_ERR_OK(ret)) {
2584                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2585                 ads_destroy(&ads);
2586                 SAFE_FREE(host_principal);
2587                 return -1;
2588         }
2589
2590         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2591
2592         if (USE_SYSTEM_KEYTAB) {
2593                 d_printf(_("Attempting to update system keytab with new password.\n"));
2594                 if (ads_keytab_create_default(ads)) {
2595                         d_printf(_("Failed to update system keytab.\n"));
2596                 }
2597         }
2598
2599         ads_destroy(&ads);
2600         SAFE_FREE(host_principal);
2601
2602         return 0;
2603 }
2604
2605 /*
2606   help for net ads search
2607 */
2608 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2609 {
2610         d_printf(_(
2611                 "\nnet ads search <expression> <attributes...>\n"
2612                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2613                 "The expression is a standard LDAP search expression, and the\n"
2614                 "attributes are a list of LDAP fields to show in the results.\n\n"
2615                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2616                 ));
2617         net_common_flags_usage(c, argc, argv);
2618         return -1;
2619 }
2620
2621
2622 /*
2623   general ADS search function. Useful in diagnosing problems in ADS
2624 */
2625 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2626 {
2627         ADS_STRUCT *ads;
2628         ADS_STATUS rc;
2629         const char *ldap_exp;
2630         const char **attrs;
2631         LDAPMessage *res = NULL;
2632
2633         if (argc < 1 || c->display_usage) {
2634                 return net_ads_search_usage(c, argc, argv);
2635         }
2636
2637         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2638                 return -1;
2639         }
2640
2641         ldap_exp = argv[0];
2642         attrs = (argv + 1);
2643
2644         rc = ads_do_search_retry(ads, ads->config.bind_path,
2645                                LDAP_SCOPE_SUBTREE,
2646                                ldap_exp, attrs, &res);
2647         if (!ADS_ERR_OK(rc)) {
2648                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2649                 ads_destroy(&ads);
2650                 return -1;
2651         }
2652
2653         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2654
2655         /* dump the results */
2656         ads_dump(ads, res);
2657
2658         ads_msgfree(ads, res);
2659         ads_destroy(&ads);
2660
2661         return 0;
2662 }
2663
2664
2665 /*
2666   help for net ads search
2667 */
2668 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2669 {
2670         d_printf(_(
2671                 "\nnet ads dn <dn> <attributes...>\n"
2672                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2673                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2674                 "to show in the results\n\n"
2675                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2676                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2677                 ));
2678         net_common_flags_usage(c, argc, argv);
2679         return -1;
2680 }
2681
2682
2683 /*
2684   general ADS search function. Useful in diagnosing problems in ADS
2685 */
2686 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2687 {
2688         ADS_STRUCT *ads;
2689         ADS_STATUS rc;
2690         const char *dn;
2691         const char **attrs;
2692         LDAPMessage *res = NULL;
2693
2694         if (argc < 1 || c->display_usage) {
2695                 return net_ads_dn_usage(c, argc, argv);
2696         }
2697
2698         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2699                 return -1;
2700         }
2701
2702         dn = argv[0];
2703         attrs = (argv + 1);
2704
2705         rc = ads_do_search_all(ads, dn,
2706                                LDAP_SCOPE_BASE,
2707                                "(objectclass=*)", attrs, &res);
2708         if (!ADS_ERR_OK(rc)) {
2709                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2710                 ads_destroy(&ads);
2711                 return -1;
2712         }
2713
2714         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2715
2716         /* dump the results */
2717         ads_dump(ads, res);
2718
2719         ads_msgfree(ads, res);
2720         ads_destroy(&ads);
2721
2722         return 0;
2723 }
2724
2725 /*
2726   help for net ads sid search
2727 */
2728 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2729 {
2730         d_printf(_(
2731                 "\nnet ads sid <sid> <attributes...>\n"
2732                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2733                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2734                 "to show in the results\n\n"
2735                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2736                 ));
2737         net_common_flags_usage(c, argc, argv);
2738         return -1;
2739 }
2740
2741
2742 /*
2743   general ADS search function. Useful in diagnosing problems in ADS
2744 */
2745 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2746 {
2747         ADS_STRUCT *ads;
2748         ADS_STATUS rc;
2749         const char *sid_string;
2750         const char **attrs;
2751         LDAPMessage *res = NULL;
2752         struct dom_sid sid;
2753
2754         if (argc < 1 || c->display_usage) {
2755                 return net_ads_sid_usage(c, argc, argv);
2756         }
2757
2758         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2759                 return -1;
2760         }
2761
2762         sid_string = argv[0];
2763         attrs = (argv + 1);
2764
2765         if (!string_to_sid(&sid, sid_string)) {
2766                 d_fprintf(stderr, _("could not convert sid\n"));
2767                 ads_destroy(&ads);
2768                 return -1;
2769         }
2770
2771         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2772         if (!ADS_ERR_OK(rc)) {
2773                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2774                 ads_destroy(&ads);
2775                 return -1;
2776         }
2777
2778         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2779
2780         /* dump the results */
2781         ads_dump(ads, res);
2782
2783         ads_msgfree(ads, res);
2784         ads_destroy(&ads);
2785
2786         return 0;
2787 }
2788
2789 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2790 {
2791         int ret;
2792         ADS_STRUCT *ads;
2793
2794         if (c->display_usage) {
2795                 d_printf(  "%s\n"
2796                            "net ads keytab flush\n"
2797                            "    %s\n",
2798                          _("Usage:"),
2799                          _("Delete the whole keytab"));
2800                 return 0;
2801         }
2802
2803         if (!c->opt_user_specified && c->opt_password == NULL) {
2804                 net_use_krb_machine_account(c);
2805         }
2806
2807         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2808                 return -1;
2809         }
2810         ret = ads_keytab_flush(ads);
2811         ads_destroy(&ads);
2812         return ret;
2813 }
2814
2815 static int net_ads_keytab_add(struct net_context *c,
2816                               int argc,
2817                               const char **argv,
2818                               bool update_ads)
2819 {
2820         int i;
2821         int ret = 0;
2822         ADS_STRUCT *ads;
2823
2824         if (c->display_usage) {
2825                 d_printf("%s\n%s",
2826                          _("Usage:"),
2827                          _("net ads keytab add <principal> [principal ...]\n"
2828                            "  Add principals to local keytab\n"
2829                            "    principal\tKerberos principal to add to "
2830                            "keytab\n"));
2831                 return 0;
2832         }
2833
2834         d_printf(_("Processing principals to add...\n"));
2835
2836         if (!c->opt_user_specified && c->opt_password == NULL) {
2837                 net_use_krb_machine_account(c);
2838         }
2839
2840         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2841                 return -1;
2842         }
2843         for (i = 0; i < argc; i++) {
2844                 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2845         }
2846         ads_destroy(&ads);
2847         return ret;
2848 }
2849
2850 static int net_ads_keytab_add_default(struct net_context *c,
2851                                       int argc,
2852                                       const char **argv)
2853 {
2854         return net_ads_keytab_add(c, argc, argv, false);
2855 }
2856
2857 static int net_ads_keytab_add_update_ads(struct net_context *c,
2858                                          int argc,
2859                                          const char **argv)
2860 {
2861         return net_ads_keytab_add(c, argc, argv, true);
2862 }
2863
2864 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2865 {
2866         ADS_STRUCT *ads;
2867         int ret;
2868
2869         if (c->display_usage) {
2870                 d_printf(  "%s\n"
2871                            "net ads keytab create\n"
2872                            "    %s\n",
2873                          _("Usage:"),
2874                          _("Create new default keytab"));
2875                 return 0;
2876         }
2877
2878         if (!c->opt_user_specified && c->opt_password == NULL) {
2879                 net_use_krb_machine_account(c);
2880         }
2881
2882         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2883                 return -1;
2884         }
2885         ret = ads_keytab_create_default(ads);
2886         ads_destroy(&ads);
2887         return ret;
2888 }
2889
2890 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2891 {
2892         const char *keytab = NULL;
2893
2894         if (c->display_usage) {
2895                 d_printf("%s\n%s",
2896                          _("Usage:"),
2897                          _("net ads keytab list [keytab]\n"
2898                            "  List a local keytab\n"
2899                            "    keytab\tKeytab to list\n"));
2900                 return 0;
2901         }
2902
2903         if (argc >= 1) {
2904                 keytab = argv[0];
2905         }
2906
2907         return ads_keytab_list(keytab);
2908 }
2909
2910
2911 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2912 {
2913         struct functable func[] = {
2914                 {
2915                         "add",
2916                         net_ads_keytab_add_default,
2917                         NET_TRANSPORT_ADS,
2918                         N_("Add a service principal"),
2919                         N_("net ads keytab add\n"
2920                            "    Add a service principal, updates keytab file only.")
2921                 },
2922                 {
2923                         "add_update_ads",
2924                         net_ads_keytab_add_update_ads,
2925                         NET_TRANSPORT_ADS,
2926                         N_("Add a service principal"),
2927                         N_("net ads keytab add_update_ads\n"
2928                            "    Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2929                 },
2930                 {
2931                         "create",
2932                         net_ads_keytab_create,
2933                         NET_TRANSPORT_ADS,
2934                         N_("Create a fresh keytab"),
2935                         N_("net ads keytab create\n"
2936                            "    Create a fresh keytab or update existing one.")
2937                 },
2938                 {
2939                         "flush",
2940                         net_ads_keytab_flush,
2941                         NET_TRANSPORT_ADS,
2942                         N_("Remove all keytab entries"),
2943                         N_("net ads keytab flush\n"
2944                            "    Remove all keytab entries")
2945                 },
2946                 {
2947                         "list",
2948                         net_ads_keytab_list,
2949                         NET_TRANSPORT_ADS,
2950                         N_("List a keytab"),
2951                         N_("net ads keytab list\n"
2952                            "    List a keytab")
2953                 },
2954                 {NULL, NULL, 0, NULL, NULL}
2955         };
2956
2957         if (!USE_KERBEROS_KEYTAB) {
2958                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2959                     "keytab method to use keytab functions.\n"));
2960         }
2961
2962         return net_run_function(c, argc, argv, "net ads keytab", func);
2963 }
2964
2965 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2966 {
2967         int ret = -1;
2968
2969         if (c->display_usage) {
2970                 d_printf(  "%s\n"
2971                            "net ads kerberos renew\n"
2972                            "    %s\n",
2973                          _("Usage:"),
2974                          _("Renew TGT from existing credential cache"));
2975                 return 0;
2976         }
2977
2978         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2979         if (ret) {
2980                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2981                         error_message(ret));
2982         }
2983         return ret;
2984 }
2985
2986 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2987                                        struct PAC_DATA_CTR **pac_data_ctr)
2988 {
2989         NTSTATUS status;
2990         int ret = -1;
2991         const char *impersonate_princ_s = NULL;
2992         const char *local_service = NULL;
2993         int i;
2994
2995         for (i=0; i<argc; i++) {
2996                 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2997                         impersonate_princ_s = get_string_param(argv[i]);
2998                         if (impersonate_princ_s == NULL) {
2999                                 return -1;
3000                         }
3001                 }
3002                 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3003                         local_service = get_string_param(argv[i]);
3004                         if (local_service == NULL) {
3005                                 return -1;
3006                         }
3007                 }
3008         }
3009
3010         if (local_service == NULL) {
3011                 local_service = talloc_asprintf(c, "%s$@%s",
3012                                                 lp_netbios_name(), lp_realm());
3013                 if (local_service == NULL) {
3014                         goto out;
3015                 }
3016         }
3017
3018         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3019
3020         status = kerberos_return_pac(c,
3021                                      c->opt_user_name,
3022                                      c->opt_password,
3023                                      0,
3024                                      NULL,
3025                                      NULL,
3026                                      NULL,
3027                                      true,
3028                                      true,
3029                                      2592000, /* one month */
3030                                      impersonate_princ_s,
3031                                      local_service,
3032                                      NULL,
3033                                      NULL,
3034                                      pac_data_ctr);
3035         if (!NT_STATUS_IS_OK(status)) {
3036                 d_printf(_("failed to query kerberos PAC: %s\n"),
3037                         nt_errstr(status));
3038                 goto out;
3039         }
3040
3041         ret = 0;
3042  out:
3043         return ret;
3044 }
3045
3046 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3047 {
3048         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3049         int i, num_buffers;
3050         int ret = -1;
3051         enum PAC_TYPE type = 0;
3052
3053         if (c->display_usage) {
3054                 d_printf(  "%s\n"
3055                            "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3056                            "    %s\n",
3057                          _("Usage:"),
3058                          _("Dump the Kerberos PAC"));
3059                 return -1;
3060         }
3061
3062         for (i=0; i<argc; i++) {
3063                 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3064                         type = get_int_param(argv[i]);
3065                 }
3066         }
3067
3068         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3069         if (ret) {
3070                 return ret;
3071         }
3072
3073         if (type == 0) {
3074
3075                 char *s = NULL;
3076
3077                 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3078                         pac_data_ctr->pac_data);
3079                 if (s != NULL) {
3080                         d_printf(_("The Pac: %s\n"), s);
3081                         talloc_free(s);
3082                 }
3083
3084                 return 0;
3085         }
3086
3087         num_buffers = pac_data_ctr->pac_data->num_buffers;
3088
3089         for (i=0; i<num_buffers; i++) {
3090
3091                 char *s = NULL;
3092
3093                 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3094                         continue;
3095                 }
3096
3097                 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3098                                 pac_data_ctr->pac_data->buffers[i].info);
3099                 if (s != NULL) {
3100                         d_printf(_("The Pac: %s\n"), s);
3101                         talloc_free(s);
3102                 }
3103                 break;
3104         }
3105
3106         return 0;
3107 }
3108
3109 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3110 {
3111         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3112         char *filename = NULL;
3113         int ret = -1;
3114         int i;
3115
3116         if (c->display_usage) {
3117                 d_printf(  "%s\n"
3118                            "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3119                            "    %s\n",
3120                          _("Usage:"),
3121                          _("Save the Kerberos PAC"));
3122                 return -1;
3123         }
3124
3125         for (i=0; i<argc; i++) {
3126                 if (strnequal(argv[i], "filename", strlen("filename"))) {
3127                         filename = get_string_param(argv[i]);
3128                         if (filename == NULL) {
3129                                 return -1;
3130                         }
3131                 }
3132         }
3133
3134         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3135         if (ret) {
3136                 return ret;
3137         }
3138
3139         if (filename == NULL) {
3140                 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3141                 return -1;
3142         }
3143
3144         /* save the raw format */
3145         if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3146                 d_printf(_("failed to save PAC in %s\n"), filename);
3147                 return -1;
3148         }
3149
3150         return 0;
3151 }
3152
3153 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3154 {
3155         struct functable func[] = {
3156                 {
3157                         "dump",
3158                         net_ads_kerberos_pac_dump,
3159                         NET_TRANSPORT_ADS,
3160                         N_("Dump Kerberos PAC"),
3161                         N_("net ads kerberos pac dump\n"
3162                            "    Dump a Kerberos PAC to stdout")
3163                 },
3164                 {
3165                         "save",
3166                         net_ads_kerberos_pac_save,
3167                         NET_TRANSPORT_ADS,
3168                         N_("Save Kerberos PAC"),
3169                         N_("net ads kerberos pac save\n"
3170                            "    Save a Kerberos PAC in a file")
3171                 },
3172
3173                 {NULL, NULL, 0, NULL, NULL}
3174         };
3175
3176         return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3177 }
3178
3179 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3180 {
3181         TALLOC_CTX *mem_ctx = NULL;
3182         int ret = -1;
3183         NTSTATUS status;
3184
3185         if (c->display_usage) {
3186                 d_printf(  "%s\n"
3187                            "net ads kerberos kinit\n"
3188                            "    %s\n",
3189                          _("Usage:"),
3190                          _("Get Ticket Granting Ticket (TGT) for the user"));
3191                 return 0;
3192         }
3193
3194         mem_ctx = talloc_init("net_ads_kerberos_kinit");
3195         if (!mem_ctx) {
3196                 goto out;
3197         }
3198
3199         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3200
3201         ret = kerberos_kinit_password_ext(c->opt_user_name,
3202                                           c->opt_password,
3203                                           0,
3204                                           NULL,
3205                                           NULL,
3206                                           NULL,
3207                                           true,
3208                                           true,
3209                                           2592000, /* one month */
3210                                           NULL,
3211                                           NULL,
3212                                           NULL,
3213                                           &status);
3214         if (ret) {
3215                 d_printf(_("failed to kinit password: %s\n"),
3216                         nt_errstr(status));
3217         }
3218  out:
3219         return ret;
3220 }
3221
3222 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3223 {
3224         struct functable func[] = {
3225                 {
3226                         "kinit",
3227                         net_ads_kerberos_kinit,
3228                         NET_TRANSPORT_ADS,
3229                         N_("Retrieve Ticket Granting Ticket (TGT)"),
3230                         N_("net ads kerberos kinit\n"
3231                            "    Receive Ticket Granting Ticket (TGT)")
3232                 },
3233                 {
3234                         "renew",
3235                         net_ads_kerberos_renew,
3236                         NET_TRANSPORT_ADS,
3237                         N_("Renew Ticket Granting Ticket from credential cache"),
3238                         N_("net ads kerberos renew\n"
3239                            "    Renew Ticket Granting Ticket (TGT) from "
3240                            "credential cache")
3241                 },
3242                 {
3243                         "pac",
3244                         net_ads_kerberos_pac,
3245                         NET_TRANSPORT_ADS,
3246                         N_("Dump Kerberos PAC"),
3247                         N_("net ads kerberos pac\n"
3248                            "    Dump Kerberos PAC")
3249                 },
3250                 {NULL, NULL, 0, NULL, NULL}
3251         };
3252
3253         return net_run_function(c, argc, argv, "net ads kerberos", func);
3254 }
3255
3256 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3257 {
3258         int ret = 0;
3259         bool ok = false;
3260         ADS_STRUCT *ads = NULL;
3261         if (c->display_usage) {
3262                 d_printf("%s\n%s",
3263                          _("Usage:"),
3264                          _("net ads setspn list <machinename>\n"));
3265                 ret = 0;
3266                 goto done;
3267         }
3268         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3269                 ret = -1;
3270                 goto done;
3271         }
3272         if (argc) {
3273                 ok = ads_setspn_list(ads, argv[0]);
3274         } else {
3275                 ok = ads_setspn_list(ads, lp_netbios_name());
3276         }
3277         if (!ok) {
3278             ret = -1;
3279         }
3280 done:
3281         if (ads) {
3282                 ads_destroy(&ads);
3283         }
3284         return ret;
3285 }
3286
3287 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3288 {
3289         int ret = 0;
3290         bool ok = false;
3291         ADS_STRUCT *ads = NULL;
3292         if (c->display_usage || argc < 1) {
3293                 d_printf("%s\n%s",
3294                          _("Usage:"),
3295                          _("net ads setspn add <machinename> SPN\n"));
3296                 ret = 0;
3297                 goto done;
3298         }
3299         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3300                 ret = -1;
3301                 goto done;
3302         }
3303         if (argc > 1) {
3304                 ok = ads_setspn_add(ads, argv[0], argv[1]);
3305         } else {
3306                 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3307         }
3308         if (!ok) {
3309             ret = -1;
3310         }
3311 done:
3312         if (ads) {
3313                 ads_destroy(&ads);
3314         }
3315         return ret;
3316 }
3317
3318 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3319 {
3320         int ret = 0;
3321         bool ok = false;
3322         ADS_STRUCT *ads = NULL;
3323         if (c->display_usage || argc < 1) {
3324                 d_printf("%s\n%s",
3325                          _("Usage:"),
3326                          _("net ads setspn delete <machinename> SPN\n"));
3327                 ret = 0;
3328                 goto done;
3329         }
3330         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3331                 ret = -1;
3332                 goto done;
3333         }
3334         if (argc > 1) {
3335                 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3336         } else {
3337                 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3338         }
3339         if (!ok) {
3340                 ret = -1;
3341         }
3342 done:
3343         if (ads) {
3344                 ads_destroy(&ads);
3345         }
3346         return ret;
3347 }
3348
3349 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3350 {
3351         struct functable func[] = {
3352                 {
3353                         "list",
3354                         net_ads_setspn_list,
3355                         NET_TRANSPORT_ADS,
3356                         N_("List Service Principal Names (SPN)"),
3357                         N_("net ads setspn list machine\n"
3358                            "    List Service Principal Names (SPN)")
3359                 },
3360                 {
3361                         "add",
3362                         net_ads_setspn_add,
3363                         NET_TRANSPORT_ADS,
3364                         N_("Add Service Principal Names (SPN)"),
3365                         N_("net ads setspn add machine spn\n"
3366                            "    Add Service Principal Names (SPN)")
3367                 },
3368                 {
3369                         "delete",
3370                         net_ads_setspn_delete,
3371                         NET_TRANSPORT_ADS,
3372                         N_("Delete Service Principal Names (SPN)"),
3373                         N_("net ads setspn delete machine spn\n"
3374                            "    Delete Service Principal Names (SPN)")
3375                 },
3376                 {NULL, NULL, 0, NULL, NULL}
3377         };
3378
3379         return net_run_function(c, argc, argv, "net ads setspn", func);
3380 }
3381
3382 static int net_ads_enctype_lookup_account(struct net_context *c,
3383                                           ADS_STRUCT *ads,
3384                                           const char *account,
3385                                           LDAPMessage **res,
3386                                           const char **enctype_str)
3387 {
3388         const char *filter;
3389         const char *attrs[] = {
3390                 "msDS-SupportedEncryptionTypes",
3391                 NULL
3392         };
3393         int count;
3394         int ret = -1;
3395         ADS_STATUS status;
3396
3397         filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3398                                  account);
3399         if (filter == NULL) {
3400                 goto done;
3401         }
3402
3403         status = ads_search(ads, res, filter, attrs);
3404         if (!ADS_ERR_OK(status)) {
3405                 d_printf(_("no account found with filter: %s\n"), filter);
3406                 goto done;
3407         }
3408
3409         count = ads_count_replies(ads, *res);
3410         switch (count) {
3411         case 1:
3412                 break;
3413         case 0:
3414                 d_printf(_("no account found with filter: %s\n"), filter);
3415                 goto done;
3416         default:
3417                 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3418                 goto done;
3419         }
3420
3421         if (enctype_str) {
3422                 *enctype_str = ads_pull_string(ads, c, *res,
3423                                                "msDS-SupportedEncryptionTypes");
3424                 if (*enctype_str == NULL) {
3425                         d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3426                         goto done;
3427                 }
3428         }
3429
3430         ret = 0;
3431  done:
3432         return ret;
3433 }
3434
3435 static void net_ads_enctype_dump_enctypes(const char *username,
3436                                           const char *enctype_str)
3437 {
3438         int enctypes = atoi(enctype_str);
3439
3440         d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3441                 username, enctypes, enctypes);
3442
3443         printf("[%s] 0x%08x DES-CBC-CRC\n",
3444                 enctypes & ENC_CRC32 ? "X" : " ",
3445                 ENC_CRC32);
3446         printf("[%s] 0x%08x DES-CBC-MD5\n",
3447                 enctypes & ENC_RSA_MD5 ? "X" : " ",
3448                 ENC_RSA_MD5);
3449         printf("[%s] 0x%08x RC4-HMAC\n",
3450                 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3451                 ENC_RC4_HMAC_MD5);
3452         printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3453                 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3454                 ENC_HMAC_SHA1_96_AES128);
3455         printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3456                 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3457                 ENC_HMAC_SHA1_96_AES256);
3458 }
3459
3460 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3461 {
3462         int ret = -1;
3463         ADS_STATUS status;
3464         ADS_STRUCT *ads = NULL;
3465         LDAPMessage *res = NULL;
3466         const char *str = NULL;
3467
3468         if (c->display_usage || (argc < 1)) {
3469                 d_printf(  "%s\n"
3470                            "net ads enctypes list\n"
3471                            "    %s\n",
3472                          _("Usage:"),
3473                          _("List supported enctypes"));
3474                 return 0;
3475         }
3476
3477         status = ads_startup(c, false, &ads);
3478         if (!ADS_ERR_OK(status)) {
3479                 printf("startup failed\n");
3480                 return ret;
3481         }
3482
3483         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3484         if (ret) {
3485                 goto done;
3486         }
3487
3488         net_ads_enctype_dump_enctypes(argv[0], str);
3489
3490         ret = 0;
3491  done:
3492         ads_msgfree(ads, res);
3493         ads_destroy(&ads);
3494
3495         return ret;
3496 }
3497
3498 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3499 {
3500         int ret = -1;
3501         ADS_STATUS status;
3502         ADS_STRUCT *ads;
3503         LDAPMessage *res = NULL;
3504         const char *etype_list_str;
3505         const char *dn;
3506         ADS_MODLIST mods;
3507         uint32_t etype_list;
3508         const char *str;
3509
3510         if (c->display_usage || argc < 1) {
3511                 d_printf(  "%s\n"
3512                            "net ads enctypes set <sAMAccountName> [enctypes]\n"
3513                            "    %s\n",
3514                          _("Usage:"),
3515                          _("Set supported enctypes"));
3516                 return 0;
3517         }
3518
3519         status = ads_startup(c, false, &ads);
3520         if (!ADS_ERR_OK(status)) {
3521                 printf("startup failed\n");
3522                 return ret;
3523         }
3524
3525         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3526         if (ret) {
3527                 goto done;
3528         }
3529
3530         dn = ads_get_dn(ads, c, res);
3531         if (dn == NULL) {
3532                 goto done;
3533         }
3534
3535         etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3536 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3537         etype_list |= ENC_HMAC_SHA1_96_AES128;
3538 #endif
3539 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3540         etype_list |= ENC_HMAC_SHA1_96_AES256;
3541 #endif
3542
3543         if (argv[1] != NULL) {
3544                 sscanf(argv[1], "%i", &etype_list);
3545         }
3546
3547         etype_list_str = talloc_asprintf(c, "%d", etype_list);
3548         if (!etype_list_str) {
3549                 goto done;
3550         }
3551
3552         mods = ads_init_mods(c);
3553         if (!mods) {
3554                 goto done;
3555         }
3556
3557         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3558                              etype_list_str);
3559         if (!ADS_ERR_OK(status)) {
3560                 goto done;
3561         }
3562
3563         status = ads_gen_mod(ads, dn, mods);
3564         if (!ADS_ERR_OK(status)) {
3565                 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3566                         ads_errstr(status));
3567                 goto done;
3568         }
3569
3570         ads_msgfree(ads, res);
3571
3572         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3573         if (ret) {
3574                 goto done;
3575         }
3576
3577         net_ads_enctype_dump_enctypes(argv[0], str);
3578
3579         ret = 0;
3580  done:
3581         ads_msgfree(ads, res);
3582         ads_destroy(&ads);
3583
3584         return ret;
3585 }
3586
3587 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3588 {
3589         int ret = -1;
3590         ADS_STATUS status;
3591         ADS_STRUCT *ads;
3592         LDAPMessage *res = NULL;
3593         const char *dn;
3594         ADS_MODLIST mods;
3595
3596         if (c->display_usage || argc < 1) {
3597                 d_printf(  "%s\n"
3598                            "net ads enctypes delete <sAMAccountName>\n"
3599                            "    %s\n",
3600                          _("Usage:"),
3601                          _("Delete supported enctypes"));
3602                 return 0;
3603         }
3604
3605         status = ads_startup(c, false, &ads);
3606         if (!ADS_ERR_OK(status)) {
3607                 printf("startup failed\n");
3608                 return ret;
3609         }
3610
3611         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3612         if (ret) {
3613                 goto done;
3614         }
3615
3616         dn = ads_get_dn(ads, c, res);
3617         if (dn == NULL) {
3618                 goto done;
3619         }
3620
3621         mods = ads_init_mods(c);
3622         if (!mods) {
3623                 goto done;
3624         }
3625
3626         status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3627         if (!ADS_ERR_OK(status)) {
3628                 goto done;
3629         }
3630
3631         status = ads_gen_mod(ads, dn, mods);
3632         if (!ADS_ERR_OK(status)) {
3633                 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3634                         ads_errstr(status));
3635                 goto done;
3636         }
3637
3638         ret = 0;
3639
3640  done:
3641         ads_msgfree(ads, res);
3642         ads_destroy(&ads);
3643         return ret;
3644 }
3645
3646 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3647 {
3648         struct functable func[] = {
3649                 {
3650                         "list",
3651                         net_ads_enctypes_list,
3652                         NET_TRANSPORT_ADS,
3653                         N_("List the supported encryption types"),
3654                         N_("net ads enctypes list\n"
3655                            "    List the supported encryption types")
3656                 },
3657                 {
3658                         "set",
3659                         net_ads_enctypes_set,
3660                         NET_TRANSPORT_ADS,
3661                         N_("Set the supported encryption types"),
3662                         N_("net ads enctypes set\n"
3663                            "    Set the supported encryption types")
3664                 },
3665                 {
3666                         "delete",
3667                         net_ads_enctypes_delete,
3668                         NET_TRANSPORT_ADS,
3669                         N_("Delete the supported encryption types"),
3670                         N_("net ads enctypes delete\n"
3671                            "    Delete the supported encryption types")
3672                 },
3673
3674                 {NULL, NULL, 0, NULL, NULL}
3675         };
3676
3677         return net_run_function(c, argc, argv, "net ads enctypes", func);
3678 }
3679
3680
3681 int net_ads(struct net_context *c, int argc, const char **argv)
3682 {
3683         struct functable func[] = {
3684                 {
3685                         "info",
3686                         net_ads_info,
3687                         NET_TRANSPORT_ADS,
3688                         N_("Display details on remote ADS server"),
3689                         N_("net ads info\n"
3690                            "    Display details on remote ADS server")
3691                 },
3692                 {
3693                         "join",
3694                         net_ads_join,
3695                         NET_TRANSPORT_ADS,
3696                         N_("Join the local machine to ADS realm"),
3697                         N_("net ads join\n"
3698                            "    Join the local machine to ADS realm")
3699                 },
3700                 {
3701                         "testjoin",
3702                         net_ads_testjoin,
3703                         NET_TRANSPORT_ADS,
3704                         N_("Validate machine account"),
3705                         N_("net ads testjoin\n"
3706                            "    Validate machine account")
3707                 },
3708                 {
3709                         "leave",
3710                         net_ads_leave,
3711                         NET_TRANSPORT_ADS,
3712                         N_("Remove the local machine from ADS"),
3713                         N_("net ads leave\n"
3714                            "    Remove the local machine from ADS")
3715                 },
3716                 {
3717                         "status",
3718                         net_ads_status,
3719                         NET_TRANSPORT_ADS,
3720                         N_("Display machine account details"),
3721                         N_("net ads status\n"
3722                            "    Display machine account details")
3723                 },
3724                 {
3725                         "user",
3726                         net_ads_user,
3727                         NET_TRANSPORT_ADS,
3728                         N_("List/modify users"),
3729                         N_("net ads user\n"
3730                            "    List/modify users")
3731                 },
3732                 {
3733                         "group",
3734                         net_ads_group,
3735                         NET_TRANSPORT_ADS,
3736                         N_("List/modify groups"),
3737                         N_("net ads group\n"
3738                            "    List/modify groups")
3739                 },
3740                 {
3741                         "dns",
3742                         net_ads_dns,
3743                         NET_TRANSPORT_ADS,
3744                         N_("Issue dynamic DNS update"),
3745                         N_("net ads dns\n"
3746                            "    Issue dynamic DNS update")
3747                 },
3748                 {
3749                         "password",
3750                         net_ads_password,
3751                         NET_TRANSPORT_ADS,
3752                         N_("Change user passwords"),
3753                         N_("net ads password\n"
3754                            "    Change user passwords")
3755                 },
3756                 {
3757                         "changetrustpw",
3758                         net_ads_changetrustpw,
3759                         NET_TRANSPORT_ADS,
3760                         N_("Change trust account password"),
3761                         N_("net ads changetrustpw\n"
3762                            "    Change trust account password")
3763                 },
3764                 {
3765                         "printer",
3766                         net_ads_printer,
3767                         NET_TRANSPORT_ADS,
3768                         N_("List/modify printer entries"),
3769                         N_("net ads printer\n"
3770                            "    List/modify printer entries")
3771                 },
3772                 {
3773                         "search",
3774                         net_ads_search,
3775                         NET_TRANSPORT_ADS,
3776                         N_("Issue LDAP search using filter"),
3777                         N_("net ads search\n"
3778                            "    Issue LDAP search using filter")
3779                 },
3780                 {
3781                         "dn",
3782                         net_ads_dn,
3783                         NET_TRANSPORT_ADS,
3784                         N_("Issue LDAP search by DN"),
3785                         N_("net ads dn\n"
3786                            "    Issue LDAP search by DN")
3787                 },
3788                 {
3789                         "sid",
3790                         net_ads_sid,
3791                         NET_TRANSPORT_ADS,
3792                         N_("Issue LDAP search by SID"),
3793                         N_("net ads sid\n"
3794                            "    Issue LDAP search by SID")
3795                 },
3796                 {
3797                         "workgroup",
3798                         net_ads_workgroup,
3799                         NET_TRANSPORT_ADS,
3800                         N_("Display workgroup name"),
3801                         N_("net ads workgroup\n"
3802                            "    Display the workgroup name")
3803                 },
3804                 {
3805                         "lookup",
3806                         net_ads_lookup,
3807                         NET_TRANSPORT_ADS,
3808                         N_("Perform CLDAP query on DC"),
3809                         N_("net ads lookup\n"
3810                            "    Find the ADS DC using CLDAP lookups")
3811                 },
3812                 {
3813                         "keytab",
3814                         net_ads_keytab,
3815                         NET_TRANSPORT_ADS,
3816                         N_("Manage local keytab file"),
3817                         N_("net ads keytab\n"
3818                            "    Manage local keytab file")
3819                 },
3820                 {
3821                         "setspn",
3822                         net_ads_setspn,
3823                         NET_TRANSPORT_ADS,
3824                         N_("Manage Service Principal Names (SPN)s"),
3825                         N_("net ads spnset\n"
3826                            "    Manage Service Principal Names (SPN)s")
3827                 },
3828                 {
3829                         "gpo",
3830                         net_ads_gpo,
3831                         NET_TRANSPORT_ADS,
3832                         N_("Manage group policy objects"),
3833                         N_("net ads gpo\n"
3834                            "    Manage group policy objects")
3835                 },
3836                 {
3837                         "kerberos",
3838                         net_ads_kerberos,
3839                         NET_TRANSPORT_ADS,
3840                         N_("Manage kerberos keytab"),
3841                         N_("net ads kerberos\n"
3842                            "    Manage kerberos keytab")
3843                 },
3844                 {
3845                         "enctypes",
3846                         net_ads_enctypes,
3847                         NET_TRANSPORT_ADS,
3848                         N_("List/modify supported encryption types"),
3849                         N_("net ads enctypes\n"
3850                            "    List/modify enctypes")
3851                 },
3852                 {NULL, NULL, 0, NULL, NULL}
3853         };
3854
3855         return net_run_function(c, argc, argv, "net ads", func);
3856 }
3857
3858 #else
3859
3860 static int net_ads_noads(void)
3861 {
3862         d_fprintf(stderr, _("ADS support not compiled in\n"));
3863         return -1;
3864 }
3865
3866 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3867 {
3868         return net_ads_noads();
3869 }
3870
3871 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3872 {
3873         return net_ads_noads();
3874 }
3875
3876 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3877 {
3878         return net_ads_noads();
3879 }
3880
3881 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3882 {
3883         return net_ads_noads();
3884 }
3885
3886 int net_ads_join(struct net_context *c, int argc, const char **argv)
3887 {
3888         return net_ads_noads();
3889 }
3890
3891 int net_ads_user(struct net_context *c, int argc, const char **argv)
3892 {
3893         return net_ads_noads();
3894 }
3895
3896 int net_ads_group(struct net_context *c, int argc, const char **argv)
3897 {
3898         return net_ads_noads();
3899 }
3900
3901 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3902 {
3903         return net_ads_noads();
3904 }
3905
3906 /* this one shouldn't display a message */
3907 int net_ads_check(struct net_context *c)
3908 {
3909         return -1;
3910 }
3911
3912 int net_ads_check_our_domain(struct net_context *c)
3913 {
3914         return -1;
3915 }
3916
3917 int net_ads(struct net_context *c, int argc, const char **argv)
3918 {
3919         return net_ads_noads();
3920 }
3921
3922 #endif  /* HAVE_ADS */