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