s3:libads: Allocate ads->config.realm under ADS_STRUCT talloc context
[gd/samba/.git] / source3 / utils / net_ads.c
1 /*
2    Samba Unix/Linux SMB client library
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "libsmb/namequery.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "nsswitch/libwbclient/wbclient.h"
30 #include "ads.h"
31 #include "libads/cldap.h"
32 #include "../lib/addns/dnsquery.h"
33 #include "../libds/common/flags.h"
34 #include "librpc/gen_ndr/libnet_join.h"
35 #include "libnet/libnet_join.h"
36 #include "smb_krb5.h"
37 #include "secrets.h"
38 #include "krb5_env.h"
39 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "lib/param/loadparm.h"
42 #include "utils/net_dns.h"
43 #include "auth/kerberos/pac_utils.h"
44 #include "lib/util/string_wrappers.h"
45
46 #ifdef HAVE_JANSSON
47 #include <jansson.h>
48 #include "audit_logging.h" /* various JSON helpers */
49 #include "auth/common_auth.h"
50 #endif /* [HAVE_JANSSON] */
51
52 #ifdef HAVE_ADS
53
54 /* when we do not have sufficient input parameters to contact a remote domain
55  * we always fall back to our own realm - Guenther*/
56
57 static const char *assume_own_realm(struct net_context *c)
58 {
59         if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
60                 return lp_realm();
61         }
62
63         return NULL;
64 }
65
66 #ifdef HAVE_JANSSON
67
68 /*
69  * note: JSON output deliberately bypasses gettext so as to provide the same
70  * output irrespective of the locale.
71  */
72
73 static int output_json(const struct json_object *jsobj)
74 {
75         TALLOC_CTX *ctx = NULL;
76         char *json = NULL;
77
78         if (json_is_invalid(jsobj)) {
79                 return -1;
80         }
81
82         ctx = talloc_new(NULL);
83         if (ctx == NULL) {
84                 d_fprintf(stderr, _("Out of memory\n"));
85                 return -1;
86         }
87
88         json = json_to_string(ctx, jsobj);
89         if (!json) {
90                 d_fprintf(stderr, _("error encoding to JSON\n"));
91                 return -1;
92         }
93
94         d_printf("%s\n", json);
95         TALLOC_FREE(ctx);
96
97         return 0;
98 }
99
100 static int net_ads_cldap_netlogon_json
101         (ADS_STRUCT *ads,
102          const char *addr,
103          const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
104 {
105         struct json_object jsobj = json_new_object();
106         struct json_object flagsobj = json_new_object();
107         char response_type [32] = { '\0' };
108         int ret = 0;
109
110         if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111                 d_fprintf(stderr, _("error setting up JSON value\n"));
112
113                 goto failure;
114         }
115
116         switch (reply->command) {
117                 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
118                         strncpy(response_type,
119                                 "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
120                                 sizeof(response_type));
121                         break;
122                 case LOGON_SAM_LOGON_RESPONSE_EX:
123                         strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
124               sizeof(response_type));
125                         break;
126                 default:
127                         snprintf(response_type, sizeof(response_type), "0x%x",
128                reply->command);
129                         break;
130         }
131
132         ret = json_add_string(&jsobj, "Information for Domain Controller",
133                               addr);
134         if (ret != 0) {
135                 goto failure;
136         }
137
138         ret = json_add_string(&jsobj, "Response Type", response_type);
139         if (ret != 0) {
140                 goto failure;
141         }
142
143         ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
144         if (ret != 0) {
145                 goto failure;
146         }
147
148         ret = json_add_bool(&flagsobj, "Is a PDC",
149                             reply->server_type & NBT_SERVER_PDC);
150         if (ret != 0) {
151                 goto failure;
152         }
153
154         ret = json_add_bool(&flagsobj, "Is a GC of the forest",
155                             reply->server_type & NBT_SERVER_GC);
156         if (ret != 0) {
157                 goto failure;
158         }
159
160         ret = json_add_bool(&flagsobj, "Is an LDAP server",
161                             reply->server_type & NBT_SERVER_LDAP);
162         if (ret != 0) {
163                 goto failure;
164         }
165
166         ret = json_add_bool(&flagsobj, "Supports DS",
167                             reply->server_type & NBT_SERVER_DS);
168         if (ret != 0) {
169                 goto failure;
170         }
171
172         ret = json_add_bool(&flagsobj, "Is running a KDC",
173                             reply->server_type & NBT_SERVER_KDC);
174         if (ret != 0) {
175                 goto failure;
176         }
177
178         ret = json_add_bool(&flagsobj, "Is running time services",
179                             reply->server_type & NBT_SERVER_TIMESERV);
180         if (ret != 0) {
181                 goto failure;
182         }
183
184         ret = json_add_bool(&flagsobj, "Is the closest DC",
185                             reply->server_type & NBT_SERVER_CLOSEST);
186         if (ret != 0) {
187                 goto failure;
188         }
189
190         ret = json_add_bool(&flagsobj, "Is writable",
191                             reply->server_type & NBT_SERVER_WRITABLE);
192         if (ret != 0) {
193                 goto failure;
194         }
195
196         ret = json_add_bool(&flagsobj, "Has a hardware clock",
197                             reply->server_type & NBT_SERVER_GOOD_TIMESERV);
198         if (ret != 0) {
199                 goto failure;
200         }
201
202         ret = json_add_bool(&flagsobj,
203                             "Is a non-domain NC serviced by LDAP server",
204                             reply->server_type & NBT_SERVER_NDNC);
205         if (ret != 0) {
206                 goto failure;
207         }
208
209         ret = json_add_bool
210                 (&flagsobj, "Is NT6 DC that has some secrets",
211                  reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
212         if (ret != 0) {
213                 goto failure;
214         }
215
216         ret = json_add_bool
217                 (&flagsobj, "Is NT6 DC that has all secrets",
218                  reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
219         if (ret != 0) {
220                 goto failure;
221         }
222
223         ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
224                             reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
225         if (ret != 0) {
226                 goto failure;
227         }
228
229         ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
230                             reply->server_type & NBT_SERVER_DS_8);
231         if (ret != 0) {
232                 goto failure;
233         }
234
235         ret = json_add_string(&jsobj, "Forest", reply->forest);
236         if (ret != 0) {
237                 goto failure;
238         }
239
240         ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
241         if (ret != 0) {
242                 goto failure;
243         }
244
245         ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
246         if (ret != 0) {
247                 goto failure;
248         }
249
250
251         ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
252         if (ret != 0) {
253                 goto failure;
254         }
255
256         ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
257         if (ret != 0) {
258                 goto failure;
259         }
260
261         if (*reply->user_name) {
262                 ret = json_add_string(&jsobj, "User name", reply->user_name);
263                 if (ret != 0) {
264                         goto failure;
265                 }
266         }
267
268         ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
269         if (ret != 0) {
270                 goto failure;
271         }
272
273         ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
274         if (ret != 0) {
275                 goto failure;
276         }
277
278         ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
279         if (ret != 0) {
280                 goto failure;
281         }
282
283         ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
284         if (ret != 0) {
285                 goto failure;
286         }
287
288         ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
289         if (ret != 0) {
290                 goto failure;
291         }
292
293         ret = json_add_object(&jsobj, "Flags", &flagsobj);
294         if (ret != 0) {
295                 goto failure;
296         }
297
298         ret = output_json(&jsobj);
299         json_free(&jsobj); /* frees flagsobj recursively */
300
301         return ret;
302
303 failure:
304         json_free(&flagsobj);
305         json_free(&jsobj);
306
307         return ret;
308 }
309
310 #else /* [HAVE_JANSSON] */
311
312 static int net_ads_cldap_netlogon_json
313         (ADS_STRUCT *ads,
314          const char *addr,
315          const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
316 {
317         d_fprintf(stderr, _("JSON support not available\n"));
318
319         return -1;
320 }
321
322 #endif /* [HAVE_JANSSON] */
323
324 /*
325   do a cldap netlogon query
326 */
327 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
328 {
329         char addr[INET6_ADDRSTRLEN];
330         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
331
332         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
333
334         if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
335                 d_fprintf(stderr, _("CLDAP query failed!\n"));
336                 return -1;
337         }
338
339         if (c->opt_json) {
340                 return net_ads_cldap_netlogon_json(ads, addr, &reply);
341         }
342
343         d_printf(_("Information for Domain Controller: %s\n\n"),
344                 addr);
345
346         d_printf(_("Response Type: "));
347         switch (reply.command) {
348         case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
349                 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
350                 break;
351         case LOGON_SAM_LOGON_RESPONSE_EX:
352                 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
353                 break;
354         default:
355                 d_printf("0x%x\n", reply.command);
356                 break;
357         }
358
359         d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
360
361         d_printf(_("Flags:\n"
362                    "\tIs a PDC:                                   %s\n"
363                    "\tIs a GC of the forest:                      %s\n"
364                    "\tIs an LDAP server:                          %s\n"
365                    "\tSupports DS:                                %s\n"
366                    "\tIs running a KDC:                           %s\n"
367                    "\tIs running time services:                   %s\n"
368                    "\tIs the closest DC:                          %s\n"
369                    "\tIs writable:                                %s\n"
370                    "\tHas a hardware clock:                       %s\n"
371                    "\tIs a non-domain NC serviced by LDAP server: %s\n"
372                    "\tIs NT6 DC that has some secrets:            %s\n"
373                    "\tIs NT6 DC that has all secrets:             %s\n"
374                    "\tRuns Active Directory Web Services:         %s\n"
375                    "\tRuns on Windows 2012 or later:              %s\n"),
376                    (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
377                    (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
378                    (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
379                    (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
380                    (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
381                    (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
382                    (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
383                    (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
384                    (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
385                    (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
386                    (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
387                    (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
388                    (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
389                    (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
390
391
392         printf(_("Forest: %s\n"), reply.forest);
393         printf(_("Domain: %s\n"), reply.dns_domain);
394         printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
395
396         printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
397         printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
398
399         if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
400
401         printf(_("Server Site Name: %s\n"), reply.server_site);
402         printf(_("Client Site Name: %s\n"), reply.client_site);
403
404         d_printf(_("NT Version: %d\n"), reply.nt_version);
405         d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
406         d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
407
408         return 0;
409 }
410
411 /*
412   this implements the CLDAP based netlogon lookup requests
413   for finding the domain controller of a ADS domain
414 */
415 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
416 {
417         TALLOC_CTX *tmp_ctx = talloc_stackframe();
418         ADS_STRUCT *ads = NULL;
419         ADS_STATUS status;
420         int ret = -1;
421
422         if (c->display_usage) {
423                 d_printf("%s\n"
424                          "net ads lookup\n"
425                          "    %s",
426                          _("Usage:"),
427                          _("Find the ADS DC using CLDAP lookup.\n"));
428                 TALLOC_FREE(tmp_ctx);
429                 return -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         status = ads_startup(c, true, tmp_ctx, &ads);
1418         if (!ADS_ERR_OK(status)) {
1419                 goto out;
1420         }
1421
1422         status = ads_find_machine_acct(ads, &res, lp_netbios_name());
1423         if (!ADS_ERR_OK(status)) {
1424                 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"),
1425                           ads_errstr(status));
1426                 goto out;
1427         }
1428
1429         if (ads_count_replies(ads, res) == 0) {
1430                 d_fprintf(stderr, _("No machine account for '%s' found\n"),
1431                           lp_netbios_name());
1432                 goto out;
1433         }
1434
1435         ads_dump(ads, res);
1436
1437         ret = 0;
1438 out:
1439         ads_msgfree(ads, res);
1440         TALLOC_FREE(tmp_ctx);
1441         return ret;
1442 }
1443
1444 /*******************************************************************
1445  Leave an AD domain.  Windows XP disables the machine account.
1446  We'll try the same.  The old code would do an LDAP delete.
1447  That only worked using the machine creds because added the machine
1448  with full control to the computer object's ACL.
1449 *******************************************************************/
1450
1451 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1452 {
1453         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1454         struct libnet_UnjoinCtx *r = NULL;
1455         WERROR werr;
1456         int ret = -1;
1457
1458         if (c->display_usage) {
1459                 d_printf(  "%s\n"
1460                            "net ads leave [--keep-account]\n"
1461                            "    %s\n",
1462                          _("Usage:"),
1463                          _("Leave an AD domain"));
1464                 TALLOC_FREE(tmp_ctx);
1465                 return -1;
1466         }
1467
1468         if (!*lp_realm()) {
1469                 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1470                 TALLOC_FREE(tmp_ctx);
1471                 return -1;
1472         }
1473
1474         if (!c->opt_kerberos) {
1475                 use_in_memory_ccache();
1476         }
1477
1478         if (!c->msg_ctx) {
1479                 d_fprintf(stderr, _("Could not initialise message context. "
1480                         "Try running as root\n"));
1481                 goto done;
1482         }
1483
1484         werr = libnet_init_UnjoinCtx(tmp_ctx, &r);
1485         if (!W_ERROR_IS_OK(werr)) {
1486                 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1487                 goto done;
1488         }
1489
1490         r->in.debug             = true;
1491         r->in.use_kerberos      = c->opt_kerberos;
1492         r->in.dc_name           = c->opt_host;
1493         r->in.domain_name       = lp_realm();
1494         r->in.admin_account     = c->opt_user_name;
1495         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1496         r->in.modify_config     = lp_config_backend_is_registry();
1497
1498         /* Try to delete it, but if that fails, disable it.  The
1499            WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1500         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1501                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1502         if (c->opt_keep_account) {
1503                 r->in.delete_machine_account = false;
1504         } else {
1505                 r->in.delete_machine_account = true;
1506         }
1507
1508         r->in.msg_ctx           = c->msg_ctx;
1509
1510         werr = libnet_Unjoin(tmp_ctx, r);
1511         if (!W_ERROR_IS_OK(werr)) {
1512                 d_printf(_("Failed to leave domain: %s\n"),
1513                          r->out.error_string ? r->out.error_string :
1514                          get_friendly_werror_msg(werr));
1515                 goto done;
1516         }
1517
1518         if (r->out.deleted_machine_account) {
1519                 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1520                         r->in.machine_name, r->out.dns_domain_name);
1521                 ret = 0;
1522                 goto done;
1523         }
1524
1525         /* We couldn't delete it - see if the disable succeeded. */
1526         if (r->out.disabled_machine_account) {
1527                 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1528                         r->in.machine_name, r->out.dns_domain_name);
1529                 ret = 0;
1530                 goto done;
1531         }
1532
1533         /* Based on what we requested, we shouldn't get here, but if
1534            we did, it means the secrets were removed, and therefore
1535            we have left the domain */
1536         d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1537                   r->in.machine_name, r->out.dns_domain_name);
1538
1539         ret = 0;
1540  done:
1541         TALLOC_FREE(tmp_ctx);
1542         return ret;
1543 }
1544
1545 static ADS_STATUS net_ads_join_ok(struct net_context *c)
1546 {
1547         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1548         ADS_STRUCT *ads = NULL;
1549         ADS_STATUS status;
1550         fstring dc_name;
1551         struct sockaddr_storage dcip;
1552
1553         if (!secrets_init()) {
1554                 DEBUG(1,("Failed to initialise secrets database\n"));
1555                 TALLOC_FREE(tmp_ctx);
1556                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1557         }
1558
1559         net_use_krb_machine_account(c);
1560
1561         get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1562
1563         status = ads_startup(c, true, tmp_ctx, &ads);
1564         if (!ADS_ERR_OK(status)) {
1565                 goto out;
1566         }
1567
1568         status = ADS_ERROR_NT(NT_STATUS_OK);
1569 out:
1570         TALLOC_FREE(tmp_ctx);
1571         return  status;
1572 }
1573
1574 /*
1575   check that an existing join is OK
1576  */
1577 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1578 {
1579         ADS_STATUS status;
1580         use_in_memory_ccache();
1581
1582         if (c->display_usage) {
1583                 d_printf(  "%s\n"
1584                            "net ads testjoin\n"
1585                            "    %s\n",
1586                          _("Usage:"),
1587                          _("Test if the existing join is ok"));
1588                 return -1;
1589         }
1590
1591         /* Display success or failure */
1592         status = net_ads_join_ok(c);
1593         if (!ADS_ERR_OK(status)) {
1594                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1595                         get_friendly_nt_error_msg(ads_ntstatus(status)));
1596                 return -1;
1597         }
1598
1599         printf(_("Join is OK\n"));
1600         return 0;
1601 }
1602
1603 /*******************************************************************
1604   Simple config checks before beginning the join
1605  ********************************************************************/
1606
1607 static WERROR check_ads_config( void )
1608 {
1609         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1610                 d_printf(_("Host is not configured as a member server.\n"));
1611                 return WERR_INVALID_DOMAIN_ROLE;
1612         }
1613
1614         if (strlen(lp_netbios_name()) > 15) {
1615                 d_printf(_("Our netbios name can be at most 15 chars long, "
1616                            "\"%s\" is %u chars long\n"), lp_netbios_name(),
1617                          (unsigned int)strlen(lp_netbios_name()));
1618                 return WERR_INVALID_COMPUTERNAME;
1619         }
1620
1621         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1622                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1623                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1624                 return WERR_INVALID_PARAMETER;
1625         }
1626
1627         return WERR_OK;
1628 }
1629
1630 /*******************************************************************
1631  ********************************************************************/
1632
1633 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1634 {
1635         d_printf(_("net ads join [--no-dns-updates] [options]\n"
1636                    "Valid options:\n"));
1637         d_printf(_("   dnshostname=FQDN      Set the dnsHostName attribute during the join.\n"
1638                    "                         The default is in the form netbiosname.dnsdomain\n"));
1639         d_printf(_("   createupn[=UPN]       Set the userPrincipalName attribute during the join.\n"
1640                    "                         The default UPN is in the form host/netbiosname@REALM.\n"));
1641         d_printf(_("   createcomputer=OU     Precreate the computer account in a specific OU.\n"
1642                    "                         The OU string read from top to bottom without RDNs\n"
1643                    "                         and delimited by a '/'.\n"
1644                    "                         E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1645                    "                         NB: A backslash '\\' is used as escape at multiple\n"
1646                    "                             levels and may need to be doubled or even\n"
1647                    "                             quadrupled. It is not used as a separator.\n"));
1648         d_printf(_("   machinepass=PASS      Set the machine password to a specific value during\n"
1649                    "                         the join. The default password is random.\n"));
1650         d_printf(_("   osName=string         Set the operatingSystem attribute during the join.\n"));
1651         d_printf(_("   osVer=string          Set the operatingSystemVersion attribute during join.\n"
1652                    "                         NB: osName and osVer must be specified together for\n"
1653                    "                             either to take effect. The operatingSystemService\n"
1654                    "                             attribute is then also set along with the two\n"
1655                    "                             other attributes.\n"));
1656         d_printf(_("   osServicePack=string  Set the operatingSystemServicePack attribute\n"
1657                    "                         during the join.\n"
1658                    "                         NB: If not specified then by default the samba\n"
1659                    "                             version string is used instead.\n"));
1660         return -1;
1661 }
1662
1663
1664 int net_ads_join(struct net_context *c, int argc, const char **argv)
1665 {
1666         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1667         struct libnet_JoinCtx *r = NULL;
1668         const char *domain = lp_realm();
1669         WERROR werr = WERR_NERR_SETUPNOTJOINED;
1670         bool createupn = false;
1671         const char *dnshostname = NULL;
1672         const char *machineupn = NULL;
1673         const char *machine_password = NULL;
1674         const char *create_in_ou = NULL;
1675         int i;
1676         const char *os_name = NULL;
1677         const char *os_version = NULL;
1678         const char *os_servicepack = NULL;
1679         bool modify_config = lp_config_backend_is_registry();
1680         enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1681         int ret = -1;
1682
1683         if (c->display_usage) {
1684                 TALLOC_FREE(tmp_ctx);
1685                 return net_ads_join_usage(c, argc, argv);
1686         }
1687
1688         if (!modify_config) {
1689                 werr = check_ads_config();
1690                 if (!W_ERROR_IS_OK(werr)) {
1691                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1692                         goto fail;
1693                 }
1694         }
1695
1696         if (!c->opt_kerberos) {
1697                 use_in_memory_ccache();
1698         }
1699
1700         werr = libnet_init_JoinCtx(tmp_ctx, &r);
1701         if (!W_ERROR_IS_OK(werr)) {
1702                 goto fail;
1703         }
1704
1705         /* process additional command line args */
1706
1707         for ( i=0; i<argc; i++ ) {
1708                 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1709                         dnshostname = get_string_param(argv[i]);
1710                 }
1711                 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1712                         createupn = true;
1713                         machineupn = get_string_param(argv[i]);
1714                 }
1715                 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1716                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1717                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1718                                 werr = WERR_INVALID_PARAMETER;
1719                                 goto fail;
1720                         }
1721                 }
1722                 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1723                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1724                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1725                                 werr = WERR_INVALID_PARAMETER;
1726                                 goto fail;
1727                         }
1728                 }
1729                 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1730                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1731                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1732                                 werr = WERR_INVALID_PARAMETER;
1733                                 goto fail;
1734                         }
1735                 }
1736                 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1737                         if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1738                                 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1739                                 werr = WERR_INVALID_PARAMETER;
1740                                 goto fail;
1741                         }
1742                 }
1743                 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1744                         if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1745                                 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1746                                 werr = WERR_INVALID_PARAMETER;
1747                                 goto fail;
1748                         }
1749                 } else {
1750                         domain = argv[i];
1751                         if (strchr(domain, '.') == NULL) {
1752                                 domain_name_type = JoinDomNameTypeUnknown;
1753                         } else {
1754                                 domain_name_type = JoinDomNameTypeDNS;
1755                         }
1756                 }
1757         }
1758
1759         if (!*domain) {
1760                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1761                 werr = WERR_INVALID_PARAMETER;
1762                 goto fail;
1763         }
1764
1765         if (!c->msg_ctx) {
1766                 d_fprintf(stderr, _("Could not initialise message context. "
1767                         "Try running as root\n"));
1768                 werr = WERR_ACCESS_DENIED;
1769                 goto fail;
1770         }
1771
1772         /* Do the domain join here */
1773
1774         r->in.domain_name       = domain;
1775         r->in.domain_name_type  = domain_name_type;
1776         r->in.create_upn        = createupn;
1777         r->in.upn               = machineupn;
1778         r->in.dnshostname       = dnshostname;
1779         r->in.account_ou        = create_in_ou;
1780         r->in.os_name           = os_name;
1781         r->in.os_version        = os_version;
1782         r->in.os_servicepack    = os_servicepack;
1783         r->in.dc_name           = c->opt_host;
1784         r->in.admin_account     = c->opt_user_name;
1785         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1786         r->in.machine_password  = machine_password;
1787         r->in.debug             = true;
1788         r->in.use_kerberos      = c->opt_kerberos;
1789         r->in.modify_config     = modify_config;
1790         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1791                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1792                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1793         r->in.msg_ctx           = c->msg_ctx;
1794
1795         werr = libnet_Join(tmp_ctx, r);
1796         if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1797             strequal(domain, lp_realm())) {
1798                 r->in.domain_name = lp_workgroup();
1799                 r->in.domain_name_type = JoinDomNameTypeNBT;
1800                 werr = libnet_Join(tmp_ctx, r);
1801         }
1802         if (!W_ERROR_IS_OK(werr)) {
1803                 goto fail;
1804         }
1805
1806         /* Check the short name of the domain */
1807
1808         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1809                 d_printf(_("The workgroup in %s does not match the short\n"
1810                            "domain name obtained from the server.\n"
1811                            "Using the name [%s] from the server.\n"
1812                            "You should set \"workgroup = %s\" in %s.\n"),
1813                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1814                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1815         }
1816
1817         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1818
1819         if (r->out.dns_domain_name) {
1820                 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1821                         r->out.dns_domain_name);
1822         } else {
1823                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1824                         r->out.netbios_domain_name);
1825         }
1826
1827         /* print out informative error string in case there is one */
1828         if (r->out.error_string != NULL) {
1829                 d_printf("%s\n", r->out.error_string);
1830         }
1831
1832         /*
1833          * We try doing the dns update (if it was compiled in
1834          * and if it was not disabled on the command line).
1835          * If the dns update fails, we still consider the join
1836          * operation as succeeded if we came this far.
1837          */
1838         if (!c->opt_no_dns_updates) {
1839                 net_ads_join_dns_updates(c, tmp_ctx, r);
1840         }
1841
1842         ret = 0;
1843
1844 fail:
1845         if (ret != 0) {
1846                 /* issue an overall failure message at the end. */
1847                 d_printf(_("Failed to join domain: %s\n"),
1848                         r && r->out.error_string ? r->out.error_string :
1849                         get_friendly_werror_msg(werr));
1850         }
1851
1852         TALLOC_FREE(tmp_ctx);
1853
1854         return ret;
1855 }
1856
1857 /*******************************************************************
1858  ********************************************************************/
1859
1860 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1861 {
1862 #if defined(HAVE_KRB5)
1863         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1864         ADS_STRUCT *ads = NULL;
1865         ADS_STATUS status;
1866         NTSTATUS ntstatus;
1867         const char *hostname = NULL;
1868         const char **addrs_list = NULL;
1869         struct sockaddr_storage *addrs = NULL;
1870         int num_addrs = 0;
1871         int count;
1872         int ret = -1;
1873
1874 #ifdef DEVELOPER
1875         talloc_enable_leak_report();
1876 #endif
1877
1878         if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1879                 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1880                                     "detection of addresses in a clustered "
1881                                     "setup.\n"));
1882                 c->display_usage = true;
1883         }
1884
1885         if (c->display_usage) {
1886                 d_printf(  "%s\n"
1887                            "net ads dns register [hostname [IP [IP...]]]\n"
1888                            "    %s\n",
1889                          _("Usage:"),
1890                          _("Register hostname with DNS\n"));
1891                 TALLOC_FREE(tmp_ctx);
1892                 return -1;
1893         }
1894
1895         if (argc >= 1) {
1896                 hostname = argv[0];
1897         }
1898
1899         if (argc > 1) {
1900                 num_addrs = argc - 1;
1901                 addrs_list = &argv[1];
1902         } else if (lp_clustering()) {
1903                 addrs_list = lp_cluster_addresses();
1904                 num_addrs = str_list_length(addrs_list);
1905         }
1906
1907         if (num_addrs > 0) {
1908                 addrs = talloc_zero_array(tmp_ctx,
1909                                           struct sockaddr_storage,
1910                                           num_addrs);
1911                 if (addrs == NULL) {
1912                         d_fprintf(stderr, _("Error allocating memory!\n"));
1913                         goto out;
1914                 }
1915         }
1916
1917         for (count = 0; count < num_addrs; count++) {
1918                 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1919                         d_fprintf(stderr, "%s '%s'.\n",
1920                                           _("Cannot interpret address"),
1921                                           addrs_list[count]);
1922                         goto out;
1923                 }
1924         }
1925
1926         status = ads_startup(c, true, tmp_ctx, &ads);
1927         if ( !ADS_ERR_OK(status) ) {
1928                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1929                 goto out;
1930         }
1931
1932         ntstatus = net_update_dns_ext(c,
1933                                       tmp_ctx,
1934                                       ads,
1935                                       hostname,
1936                                       addrs,
1937                                       num_addrs,
1938                                       false);
1939         if (!NT_STATUS_IS_OK(ntstatus)) {
1940                 d_fprintf( stderr, _("DNS update failed!\n") );
1941                 goto out;
1942         }
1943
1944         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1945
1946         ret = 0;
1947 out:
1948         TALLOC_FREE(tmp_ctx);
1949
1950         return ret;
1951 #else
1952         d_fprintf(stderr,
1953                   _("DNS update support not enabled at compile time!\n"));
1954         return -1;
1955 #endif
1956 }
1957
1958 static int net_ads_dns_unregister(struct net_context *c,
1959                                   int argc,
1960                                   const char **argv)
1961 {
1962 #if defined(HAVE_KRB5)
1963         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1964         ADS_STRUCT *ads = NULL;
1965         ADS_STATUS status;
1966         NTSTATUS ntstatus;
1967         const char *hostname = NULL;
1968         int ret = -1;
1969
1970 #ifdef DEVELOPER
1971         talloc_enable_leak_report();
1972 #endif
1973
1974         if (argc != 1) {
1975                 c->display_usage = true;
1976         }
1977
1978         if (c->display_usage) {
1979                 d_printf(  "%s\n"
1980                            "net ads dns unregister [hostname]\n"
1981                            "    %s\n",
1982                          _("Usage:"),
1983                          _("Remove all IP Address entires for a given\n"
1984                            "    hostname from the Active Directory server.\n"));
1985                 TALLOC_FREE(tmp_ctx);
1986                 return -1;
1987         }
1988
1989         /* Get the hostname for un-registering */
1990         hostname = argv[0];
1991
1992         status = ads_startup(c, true, tmp_ctx, &ads);
1993         if ( !ADS_ERR_OK(status) ) {
1994                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1995                 goto out;
1996         }
1997
1998         ntstatus = net_update_dns_ext(c,
1999                                       tmp_ctx,
2000                                       ads,
2001                                       hostname,
2002                                       NULL,
2003                                       0,
2004                                       true);
2005         if (!NT_STATUS_IS_OK(ntstatus)) {
2006                 d_fprintf( stderr, _("DNS update failed!\n") );
2007                 goto out;
2008         }
2009
2010         d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2011
2012         ret = 0;
2013 out:
2014         TALLOC_FREE(tmp_ctx);
2015
2016         return ret;
2017 #else
2018         d_fprintf(stderr,
2019                   _("DNS update support not enabled at compile time!\n"));
2020         return -1;
2021 #endif
2022 }
2023
2024
2025 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2026 {
2027         size_t num_names = 0;
2028         char **hostnames = NULL;
2029         size_t i = 0;
2030         struct samba_sockaddr *addrs = NULL;
2031         NTSTATUS status;
2032
2033         if (argc != 1 || c->display_usage) {
2034                 d_printf(  "%s\n"
2035                            "    %s\n"
2036                            "    %s\n",
2037                          _("Usage:"),
2038                          _("net ads dns async <name>\n"),
2039                          _("  Async look up hostname from the DNS server\n"
2040                            "    hostname\tName to look up\n"));
2041                 return -1;
2042         }
2043
2044         status = ads_dns_lookup_a(talloc_tos(),
2045                                   argv[0],
2046                                   &num_names,
2047                                   &hostnames,
2048                                   &addrs);
2049         if (!NT_STATUS_IS_OK(status)) {
2050                 d_printf("Looking up A record for %s got error %s\n",
2051                          argv[0],
2052                          nt_errstr(status));
2053                 return -1;
2054         }
2055         d_printf("Async A record lookup - got %u names for %s\n",
2056                  (unsigned int)num_names,
2057                  argv[0]);
2058         for (i = 0; i < num_names; i++) {
2059                 char addr_buf[INET6_ADDRSTRLEN];
2060                 print_sockaddr(addr_buf,
2061                                sizeof(addr_buf),
2062                                &addrs[i].u.ss);
2063                 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2064                         (unsigned int)i,
2065                         hostnames[i],
2066                         addr_buf);
2067         }
2068
2069 #if defined(HAVE_IPV6)
2070         status = ads_dns_lookup_aaaa(talloc_tos(),
2071                                      argv[0],
2072                                      &num_names,
2073                                      &hostnames,
2074                                      &addrs);
2075         if (!NT_STATUS_IS_OK(status)) {
2076                 d_printf("Looking up AAAA record for %s got error %s\n",
2077                          argv[0],
2078                          nt_errstr(status));
2079                 return -1;
2080         }
2081         d_printf("Async AAAA record lookup - got %u names for %s\n",
2082                  (unsigned int)num_names,
2083                  argv[0]);
2084         for (i = 0; i < num_names; i++) {
2085                 char addr_buf[INET6_ADDRSTRLEN];
2086                 print_sockaddr(addr_buf,
2087                                sizeof(addr_buf),
2088                                &addrs[i].u.ss);
2089                 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2090                         (unsigned int)i,
2091                         hostnames[i],
2092                         addr_buf);
2093         }
2094 #endif
2095         return 0;
2096 }
2097
2098
2099 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2100 {
2101         struct functable func[] = {
2102                 {
2103                         "register",
2104                         net_ads_dns_register,
2105                         NET_TRANSPORT_ADS,
2106                         N_("Add host dns entry to AD"),
2107                         N_("net ads dns register\n"
2108                            "    Add host dns entry to AD")
2109                 },
2110                 {
2111                         "unregister",
2112                         net_ads_dns_unregister,
2113                         NET_TRANSPORT_ADS,
2114                         N_("Remove host dns entry from AD"),
2115                         N_("net ads dns unregister\n"
2116                            "    Remove host dns entry from AD")
2117                 },
2118                 {
2119                         "async",
2120                         net_ads_dns_async,
2121                         NET_TRANSPORT_ADS,
2122                         N_("Look up host"),
2123                         N_("net ads dns async\n"
2124                            "    Look up host using async DNS")
2125                 },
2126                 {NULL, NULL, 0, NULL, NULL}
2127         };
2128
2129         return net_run_function(c, argc, argv, "net ads dns", func);
2130 }
2131
2132 /*******************************************************************
2133  ********************************************************************/
2134
2135 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2136 {
2137         d_printf(_(
2138 "\nnet ads printer search <printer>"
2139 "\n\tsearch for a printer in the directory\n"
2140 "\nnet ads printer info <printer> <server>"
2141 "\n\tlookup info in directory for printer on server"
2142 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2143 "\nnet ads printer publish <printername>"
2144 "\n\tpublish printer in directory"
2145 "\n\t(note: printer name is required)\n"
2146 "\nnet ads printer remove <printername>"
2147 "\n\tremove printer from directory"
2148 "\n\t(note: printer name is required)\n"));
2149         return -1;
2150 }
2151
2152 /*******************************************************************
2153  ********************************************************************/
2154
2155 static int net_ads_printer_search(struct net_context *c,
2156                                   int argc,
2157                                   const char **argv)
2158 {
2159         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2160         ADS_STRUCT *ads = NULL;
2161         ADS_STATUS status;
2162         LDAPMessage *res = NULL;
2163         int ret = -1;
2164
2165         if (c->display_usage) {
2166                 d_printf(  "%s\n"
2167                            "net ads printer search\n"
2168                            "    %s\n",
2169                          _("Usage:"),
2170                          _("List printers in the AD"));
2171                 TALLOC_FREE(tmp_ctx);
2172                 return -1;
2173         }
2174
2175         status = ads_startup(c, false, tmp_ctx, &ads);
2176         if (!ADS_ERR_OK(status)) {
2177                 goto out;
2178         }
2179
2180         status = ads_find_printers(ads, &res);
2181         if (!ADS_ERR_OK(status)) {
2182                 d_fprintf(stderr, _("ads_find_printer: %s\n"),
2183                           ads_errstr(status));
2184                 goto out;
2185         }
2186
2187         if (ads_count_replies(ads, res) == 0) {
2188                 d_fprintf(stderr, _("No results found\n"));
2189                 goto out;
2190         }
2191
2192         ads_dump(ads, res);
2193
2194         ret = 0;
2195 out:
2196         ads_msgfree(ads, res);
2197         TALLOC_FREE(tmp_ctx);
2198         return ret;
2199 }
2200
2201 static int net_ads_printer_info(struct net_context *c,
2202                                 int argc,
2203                                 const char **argv)
2204 {
2205         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2206         ADS_STRUCT *ads = NULL;
2207         ADS_STATUS status;
2208         const char *servername = NULL;
2209         const char *printername = NULL;
2210         LDAPMessage *res = NULL;
2211         int ret = -1;
2212
2213         if (c->display_usage) {
2214                 d_printf("%s\n%s",
2215                          _("Usage:"),
2216                          _("net ads printer info [printername [servername]]\n"
2217                            "  Display printer info from AD\n"
2218                            "    printername\tPrinter name or wildcard\n"
2219                            "    servername\tName of the print server\n"));
2220                 TALLOC_FREE(tmp_ctx);
2221                 return -1;
2222         }
2223
2224         status = ads_startup(c, false, tmp_ctx, &ads);
2225         if (!ADS_ERR_OK(status)) {
2226                 goto out;
2227         }
2228
2229         if (argc > 0) {
2230                 printername = argv[0];
2231         } else {
2232                 printername = "*";
2233         }
2234
2235         if (argc > 1) {
2236                 servername =  argv[1];
2237         } else {
2238                 servername = lp_netbios_name();
2239         }
2240
2241         status = ads_find_printer_on_server(ads, &res, printername, servername);
2242         if (!ADS_ERR_OK(status)) {
2243                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2244                           servername, ads_errstr(status));
2245                 goto out;
2246         }
2247
2248         if (ads_count_replies(ads, res) == 0) {
2249                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2250                 goto out;
2251         }
2252
2253         ads_dump(ads, res);
2254
2255         ret = 0;
2256 out:
2257         ads_msgfree(ads, res);
2258         TALLOC_FREE(tmp_ctx);
2259         return ret;
2260 }
2261
2262 static int net_ads_printer_publish(struct net_context *c,
2263                                    int argc,
2264                                    const char **argv)
2265 {
2266         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2267         ADS_STRUCT *ads = NULL;
2268         ADS_STATUS status;
2269         const char *servername = NULL;
2270         const char *printername = NULL;
2271         struct cli_state *cli = NULL;
2272         struct rpc_pipe_client *pipe_hnd = NULL;
2273         struct sockaddr_storage server_ss = { 0 };
2274         NTSTATUS nt_status;
2275         ADS_MODLIST mods = NULL;
2276         char *prt_dn = NULL;
2277         char *srv_dn = NULL;
2278         char **srv_cn = NULL;
2279         char *srv_cn_escaped = NULL;
2280         char *printername_escaped = NULL;
2281         LDAPMessage *res = NULL;
2282         bool ok;
2283         int ret = -1;
2284
2285         if (argc < 1 || c->display_usage) {
2286                 d_printf("%s\n%s",
2287                          _("Usage:"),
2288                          _("net ads printer publish <printername> [servername]\n"
2289                            "  Publish printer in AD\n"
2290                            "    printername\tName of the printer\n"
2291                            "    servername\tName of the print server\n"));
2292                 TALLOC_FREE(tmp_ctx);
2293                 return -1;
2294         }
2295
2296         mods = ads_init_mods(tmp_ctx);
2297         if (mods == NULL) {
2298                 d_fprintf(stderr, _("Out of memory\n"));
2299                 goto out;
2300         }
2301
2302         status = ads_startup(c, true, tmp_ctx, &ads);
2303         if (!ADS_ERR_OK(status)) {
2304                 goto out;
2305         }
2306
2307         printername = argv[0];
2308
2309         if (argc == 2) {
2310                 servername = argv[1];
2311         } else {
2312                 servername = lp_netbios_name();
2313         }
2314
2315         /* Get printer data from SPOOLSS */
2316
2317         ok = resolve_name(servername, &server_ss, 0x20, false);
2318         if (!ok) {
2319                 d_fprintf(stderr, _("Could not find server %s\n"),
2320                           servername);
2321                 goto out;
2322         }
2323
2324         cli_credentials_set_kerberos_state(c->creds,
2325                                            CRED_USE_KERBEROS_REQUIRED,
2326                                            CRED_SPECIFIED);
2327
2328         nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2329                                         &server_ss, 0,
2330                                         "IPC$", "IPC",
2331                                         c->creds,
2332                                         CLI_FULL_CONNECTION_IPC);
2333
2334         if (NT_STATUS_IS_ERR(nt_status)) {
2335                 d_fprintf(stderr, _("Unable to open a connection to %s to "
2336                                     "obtain data for %s\n"),
2337                           servername, printername);
2338                 goto out;
2339         }
2340
2341         /* Publish on AD server */
2342
2343         ads_find_machine_acct(ads, &res, servername);
2344
2345         if (ads_count_replies(ads, res) == 0) {
2346                 d_fprintf(stderr, _("Could not find machine account for server "
2347                                     "%s\n"),
2348                          servername);
2349                 goto out;
2350         }
2351
2352         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2353         srv_cn = ldap_explode_dn(srv_dn, 1);
2354
2355         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2356         printername_escaped = escape_rdn_val_string_alloc(printername);
2357         if (!srv_cn_escaped || !printername_escaped) {
2358                 SAFE_FREE(srv_cn_escaped);
2359                 SAFE_FREE(printername_escaped);
2360                 d_fprintf(stderr, _("Internal error, out of memory!"));
2361                 goto out;
2362         }
2363
2364         prt_dn = talloc_asprintf(tmp_ctx,
2365                                  "cn=%s-%s,%s",
2366                                  srv_cn_escaped,
2367                                  printername_escaped,
2368                                  srv_dn);
2369         if (prt_dn == NULL) {
2370                 SAFE_FREE(srv_cn_escaped);
2371                 SAFE_FREE(printername_escaped);
2372                 d_fprintf(stderr, _("Internal error, out of memory!"));
2373                 goto out;
2374         }
2375
2376         SAFE_FREE(srv_cn_escaped);
2377         SAFE_FREE(printername_escaped);
2378
2379         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2380         if (!NT_STATUS_IS_OK(nt_status)) {
2381                 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2382                          servername);
2383                 goto out;
2384         }
2385
2386         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd,
2387                                                               tmp_ctx,
2388                                                               &mods,
2389                                                               printername))) {
2390                 goto out;
2391         }
2392
2393         status = ads_add_printer_entry(ads, prt_dn, tmp_ctx, &mods);
2394         if (!ADS_ERR_OK(status)) {
2395                 d_fprintf(stderr, "ads_publish_printer: %s\n",
2396                           ads_errstr(status));
2397                 goto out;
2398         }
2399
2400         d_printf("published printer\n");
2401
2402         ret = 0;
2403 out:
2404         talloc_destroy(tmp_ctx);
2405
2406         return ret;
2407 }
2408
2409 static int net_ads_printer_remove(struct net_context *c,
2410                                   int argc,
2411                                   const char **argv)
2412 {
2413         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2414         ADS_STRUCT *ads = NULL;
2415         ADS_STATUS status;
2416         const char *servername = NULL;
2417         char *prt_dn = NULL;
2418         LDAPMessage *res = NULL;
2419         int ret = -1;
2420
2421         if (argc < 1 || c->display_usage) {
2422                 d_printf("%s\n%s",
2423                          _("Usage:"),
2424                          _("net ads printer remove <printername> [servername]\n"
2425                            "  Remove a printer from the AD\n"
2426                            "    printername\tName of the printer\n"
2427                            "    servername\tName of the print server\n"));
2428                 TALLOC_FREE(tmp_ctx);
2429                 return -1;
2430         }
2431
2432         status = ads_startup(c, true, tmp_ctx, &ads);
2433         if (!ADS_ERR_OK(status)) {
2434                 goto out;
2435         }
2436
2437         if (argc > 1) {
2438                 servername = argv[1];
2439         } else {
2440                 servername = lp_netbios_name();
2441         }
2442
2443         status = ads_find_printer_on_server(ads, &res, argv[0], servername);
2444         if (!ADS_ERR_OK(status)) {
2445                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"),
2446                           ads_errstr(status));
2447                 goto out;
2448         }
2449
2450         if (ads_count_replies(ads, res) == 0) {
2451                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2452                 goto out;
2453         }
2454
2455         prt_dn = ads_get_dn(ads, tmp_ctx, res);
2456         if (prt_dn == NULL) {
2457                 d_fprintf(stderr, _("Out of memory\n"));
2458                 goto out;
2459         }
2460
2461         status = ads_del_dn(ads, prt_dn);
2462         if (!ADS_ERR_OK(status)) {
2463                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(status));
2464                 goto out;
2465         }
2466
2467         ret = 0;
2468 out:
2469         ads_msgfree(ads, res);
2470         TALLOC_FREE(tmp_ctx);
2471         return ret;
2472 }
2473
2474 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2475 {
2476         struct functable func[] = {
2477                 {
2478                         "search",
2479                         net_ads_printer_search,
2480                         NET_TRANSPORT_ADS,
2481                         N_("Search for a printer"),
2482                         N_("net ads printer search\n"
2483                            "    Search for a printer")
2484                 },
2485                 {
2486                         "info",
2487                         net_ads_printer_info,
2488                         NET_TRANSPORT_ADS,
2489                         N_("Display printer information"),
2490                         N_("net ads printer info\n"
2491                            "    Display printer information")
2492                 },
2493                 {
2494                         "publish",
2495                         net_ads_printer_publish,
2496                         NET_TRANSPORT_ADS,
2497                         N_("Publish a printer"),
2498                         N_("net ads printer publish\n"
2499                            "    Publish a printer")
2500                 },
2501                 {
2502                         "remove",
2503                         net_ads_printer_remove,
2504                         NET_TRANSPORT_ADS,
2505                         N_("Delete a printer"),
2506                         N_("net ads printer remove\n"
2507                            "    Delete a printer")
2508                 },
2509                 {NULL, NULL, 0, NULL, NULL}
2510         };
2511
2512         return net_run_function(c, argc, argv, "net ads printer", func);
2513 }
2514
2515
2516 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2517 {
2518         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2519         ADS_STRUCT *ads = NULL;
2520         const char *auth_principal = cli_credentials_get_username(c->creds);
2521         const char *auth_password = cli_credentials_get_password(c->creds);
2522         const char *realm = NULL;
2523         char *new_password = NULL;
2524         char *chr = NULL;
2525         char *prompt = NULL;
2526         const char *user = NULL;
2527         char pwd[256] = {0};
2528         ADS_STATUS status;
2529         int ret = 0;
2530
2531         if (c->display_usage) {
2532                 d_printf("%s\n%s",
2533                          _("Usage:"),
2534                          _("net ads password <username>\n"
2535                            "  Change password for user\n"
2536                            "    username\tName of user to change password for\n"));
2537                 TALLOC_FREE(tmp_ctx);
2538                 return -1;
2539         }
2540
2541         if (auth_principal == NULL || auth_password == NULL) {
2542                 d_fprintf(stderr, _("You must supply an administrator "
2543                                     "username/password\n"));
2544                 TALLOC_FREE(tmp_ctx);
2545                 return -1;
2546         }
2547
2548         if (argc < 1) {
2549                 d_fprintf(stderr, _("ERROR: You must say which username to "
2550                                     "change password for\n"));
2551                 TALLOC_FREE(tmp_ctx);
2552                 return -1;
2553         }
2554
2555         if (strchr_m(argv[0], '@')) {
2556                 user = talloc_strdup(tmp_ctx, argv[0]);
2557         } else {
2558                 user = talloc_asprintf(tmp_ctx, "%s@%s", argv[0], lp_realm());
2559         }
2560         if (user == NULL) {
2561                 d_fprintf(stderr, _("Out of memory\n"));
2562                 goto out;
2563         }
2564
2565         use_in_memory_ccache();
2566         chr = strchr_m(auth_principal, '@');
2567         if (chr) {
2568                 realm = ++chr;
2569         } else {
2570                 realm = lp_realm();
2571         }
2572
2573         /* use the realm so we can eventually change passwords for users
2574         in realms other than default */
2575         ads = ads_init(tmp_ctx,
2576                        realm,
2577                        c->opt_workgroup,
2578                        c->opt_host,
2579                        ADS_SASL_PLAIN);
2580         if (ads == NULL) {
2581                 goto out;
2582         }
2583
2584         /* we don't actually need a full connect, but it's the easy way to
2585                 fill in the KDC's addresss */
2586         ads_connect(ads);
2587
2588         if (!ads->config.realm) {
2589                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2590                 goto out;
2591         }
2592
2593         if (argv[1] != NULL) {
2594                 new_password = talloc_strdup(tmp_ctx, argv[1]);
2595         } else {
2596                 int rc;
2597
2598                 prompt = talloc_asprintf(tmp_ctx, _("Enter new password for %s:"), user);
2599                 if (prompt == NULL) {
2600                         d_fprintf(stderr, _("Out of memory\n"));
2601                         goto out;
2602                 }
2603
2604                 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2605                 if (rc < 0) {
2606                         goto out;
2607                 }
2608                 new_password = talloc_strdup(tmp_ctx, pwd);
2609                 memset(pwd, '\0', sizeof(pwd));
2610         }
2611
2612         if (new_password == NULL) {
2613                 d_fprintf(stderr, _("Out of memory\n"));
2614                 goto out;
2615         }
2616
2617         status = kerberos_set_password(ads->auth.kdc_server,
2618                                        auth_principal,
2619                                        auth_password,
2620                                        user,
2621                                        new_password,
2622                                        ads->auth.time_offset);
2623         memset(new_password, '\0', strlen(new_password));
2624         if (!ADS_ERR_OK(status)) {
2625                 d_fprintf(stderr, _("Password change failed: %s\n"),
2626                           ads_errstr(status));
2627                 goto out;
2628         }
2629
2630         d_printf(_("Password change for %s completed.\n"), user);
2631
2632         ret = 0;
2633 out:
2634         TALLOC_FREE(tmp_ctx);
2635         return ret;
2636 }
2637
2638 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2639 {
2640         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2641         ADS_STRUCT *ads = NULL;
2642         char *host_principal = NULL;
2643         char *my_name = NULL;
2644         ADS_STATUS status;
2645         int ret = -1;
2646
2647         if (c->display_usage) {
2648                 d_printf(  "%s\n"
2649                            "net ads changetrustpw\n"
2650                            "    %s\n",
2651                          _("Usage:"),
2652                          _("Change the machine account's trust password"));
2653                 TALLOC_FREE(tmp_ctx);
2654                 return -1;
2655         }
2656
2657         if (!secrets_init()) {
2658                 DEBUG(1,("Failed to initialise secrets database\n"));
2659                 goto out;
2660         }
2661
2662         net_use_krb_machine_account(c);
2663
2664         use_in_memory_ccache();
2665
2666         status = ads_startup(c, true, tmp_ctx, &ads);
2667         if (!ADS_ERR_OK(status)) {
2668                 goto out;
2669         }
2670
2671         my_name = talloc_asprintf_strlower_m(tmp_ctx, "%s", lp_netbios_name());
2672         if (my_name == NULL) {
2673                 d_fprintf(stderr, _("Out of memory\n"));
2674                 goto out;
2675         }
2676
2677         host_principal = talloc_asprintf(tmp_ctx, "%s$@%s", my_name, ads->config.realm);
2678         if (host_principal == NULL) {
2679                 d_fprintf(stderr, _("Out of memory\n"));
2680                 goto out;
2681         }
2682
2683         d_printf(_("Changing password for principal: %s\n"), host_principal);
2684
2685         status = ads_change_trust_account_password(ads, host_principal);
2686         if (!ADS_ERR_OK(status)) {
2687                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(status));
2688                 goto out;
2689         }
2690
2691         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2692
2693         if (USE_SYSTEM_KEYTAB) {
2694                 d_printf(_("Attempting to update system keytab with new password.\n"));
2695                 if (ads_keytab_create_default(ads)) {
2696                         d_printf(_("Failed to update system keytab.\n"));
2697                 }
2698         }
2699
2700         ret = 0;
2701 out:
2702         TALLOC_FREE(tmp_ctx);
2703
2704         return ret;
2705 }
2706
2707 /*
2708   help for net ads search
2709 */
2710 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2711 {
2712         d_printf(_(
2713                 "\nnet ads search <expression> <attributes...>\n"
2714                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2715                 "The expression is a standard LDAP search expression, and the\n"
2716                 "attributes are a list of LDAP fields to show in the results.\n\n"
2717                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2718                 ));
2719         net_common_flags_usage(c, argc, argv);
2720         return -1;
2721 }
2722
2723
2724 /*
2725   general ADS search function. Useful in diagnosing problems in ADS
2726 */
2727 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2728 {
2729         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2730         ADS_STRUCT *ads = NULL;
2731         ADS_STATUS status;
2732         const char *ldap_exp = NULL;
2733         const char **attrs = NULL;
2734         LDAPMessage *res = NULL;
2735         int ret = -1;
2736
2737         if (argc < 1 || c->display_usage) {
2738                 TALLOC_FREE(tmp_ctx);
2739                 return net_ads_search_usage(c, argc, argv);
2740         }
2741
2742         status = ads_startup(c, false, tmp_ctx, &ads);
2743         if (!ADS_ERR_OK(status)) {
2744                 goto out;
2745         }
2746
2747         ldap_exp = argv[0];
2748         attrs = (argv + 1);
2749
2750         status = ads_do_search_retry(ads,
2751                                      ads->config.bind_path,
2752                                      LDAP_SCOPE_SUBTREE,
2753                                      ldap_exp,
2754                                      attrs,
2755                                      &res);
2756         if (!ADS_ERR_OK(status)) {
2757                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2758                 goto out;
2759         }
2760
2761         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2762
2763         /* dump the results */
2764         ads_dump(ads, res);
2765
2766         ret = 0;
2767 out:
2768         ads_msgfree(ads, res);
2769         TALLOC_FREE(tmp_ctx);
2770         return ret;
2771 }
2772
2773
2774 /*
2775   help for net ads search
2776 */
2777 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2778 {
2779         d_printf(_(
2780                 "\nnet ads dn <dn> <attributes...>\n"
2781                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2782                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2783                 "to show in the results\n\n"
2784                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2785                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2786                 ));
2787         net_common_flags_usage(c, argc, argv);
2788         return -1;
2789 }
2790
2791
2792 /*
2793   general ADS search function. Useful in diagnosing problems in ADS
2794 */
2795 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2796 {
2797         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2798         ADS_STRUCT *ads = NULL;
2799         ADS_STATUS status;
2800         const char *dn = NULL;
2801         const char **attrs = NULL;
2802         LDAPMessage *res = NULL;
2803         int ret = -1;
2804
2805         if (argc < 1 || c->display_usage) {
2806                 TALLOC_FREE(tmp_ctx);
2807                 return net_ads_dn_usage(c, argc, argv);
2808         }
2809
2810         status = ads_startup(c, false, tmp_ctx, &ads);
2811         if (!ADS_ERR_OK(status)) {
2812                 goto out;
2813         }
2814
2815         dn = argv[0];
2816         attrs = (argv + 1);
2817
2818         status = ads_do_search_all(ads,
2819                                    dn,
2820                                    LDAP_SCOPE_BASE,
2821                                    "(objectclass=*)",
2822                                    attrs,
2823                                    &res);
2824         if (!ADS_ERR_OK(status)) {
2825                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2826                 goto out;
2827         }
2828
2829         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2830
2831         /* dump the results */
2832         ads_dump(ads, res);
2833
2834         ret = 0;
2835 out:
2836         ads_msgfree(ads, res);
2837         TALLOC_FREE(tmp_ctx);
2838         return ret;
2839 }
2840
2841 /*
2842   help for net ads sid search
2843 */
2844 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2845 {
2846         d_printf(_(
2847                 "\nnet ads sid <sid> <attributes...>\n"
2848                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2849                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2850                 "to show in the results\n\n"
2851                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2852                 ));
2853         net_common_flags_usage(c, argc, argv);
2854         return -1;
2855 }
2856
2857
2858 /*
2859   general ADS search function. Useful in diagnosing problems in ADS
2860 */
2861 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2862 {
2863         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2864         ADS_STRUCT *ads = NULL;
2865         ADS_STATUS status;
2866         const char *sid_string = NULL;
2867         const char **attrs = NULL;
2868         LDAPMessage *res = NULL;
2869         struct dom_sid sid = { 0 };
2870         int ret = -1;
2871
2872         if (argc < 1 || c->display_usage) {
2873                 TALLOC_FREE(tmp_ctx);
2874                 return net_ads_sid_usage(c, argc, argv);
2875         }
2876
2877         status = ads_startup(c, false, tmp_ctx, &ads);
2878         if (!ADS_ERR_OK(status)) {
2879                 goto out;
2880         }
2881
2882         sid_string = argv[0];
2883         attrs = (argv + 1);
2884
2885         if (!string_to_sid(&sid, sid_string)) {
2886                 d_fprintf(stderr, _("could not convert sid\n"));
2887                 goto out;
2888         }
2889
2890         status = ads_search_retry_sid(ads, &res, &sid, attrs);
2891         if (!ADS_ERR_OK(status)) {
2892                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2893                 goto out;
2894         }
2895
2896         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2897
2898         /* dump the results */
2899         ads_dump(ads, res);
2900
2901         ret = 0;
2902 out:
2903         ads_msgfree(ads, res);
2904         TALLOC_FREE(tmp_ctx);
2905         return ret;
2906 }
2907
2908 static int net_ads_keytab_flush(struct net_context *c,
2909                                 int argc,
2910                                 const char **argv)
2911 {
2912         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2913         ADS_STRUCT *ads = NULL;
2914         ADS_STATUS status;
2915         int ret = -1;
2916
2917         if (c->display_usage) {
2918                 d_printf(  "%s\n"
2919                            "net ads keytab flush\n"
2920                            "    %s\n",
2921                          _("Usage:"),
2922                          _("Delete the whole keytab"));
2923                 TALLOC_FREE(tmp_ctx);
2924                 return -1;
2925         }
2926
2927         if (!c->opt_user_specified && c->opt_password == NULL) {
2928                 net_use_krb_machine_account(c);
2929         }
2930
2931         status = ads_startup(c, true, tmp_ctx, &ads);
2932         if (!ADS_ERR_OK(status)) {
2933                 goto out;
2934         }
2935
2936         ret = ads_keytab_flush(ads);
2937 out:
2938         TALLOC_FREE(tmp_ctx);
2939         return ret;
2940 }
2941
2942 static int net_ads_keytab_add(struct net_context *c,
2943                               int argc,
2944                               const char **argv,
2945                               bool update_ads)
2946 {
2947         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2948         ADS_STRUCT *ads = NULL;
2949         ADS_STATUS status;
2950         int i;
2951         int ret = -1;
2952
2953         if (c->display_usage) {
2954                 d_printf("%s\n%s",
2955                          _("Usage:"),
2956                          _("net ads keytab add <principal> [principal ...]\n"
2957                            "  Add principals to local keytab\n"
2958                            "    principal\tKerberos principal to add to "
2959                            "keytab\n"));
2960                 TALLOC_FREE(tmp_ctx);
2961                 return -1;
2962         }
2963
2964         d_printf(_("Processing principals to add...\n"));
2965
2966         if (!c->opt_user_specified && c->opt_password == NULL) {
2967                 net_use_krb_machine_account(c);
2968         }
2969
2970         status = ads_startup(c, true, tmp_ctx, &ads);
2971         if (!ADS_ERR_OK(status)) {
2972                 goto out;
2973         }
2974
2975         for (ret = 0, i = 0; i < argc; i++) {
2976                 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2977         }
2978 out:
2979         TALLOC_FREE(tmp_ctx);
2980         return ret;
2981 }
2982
2983 static int net_ads_keytab_add_default(struct net_context *c,
2984                                       int argc,
2985                                       const char **argv)
2986 {
2987         return net_ads_keytab_add(c, argc, argv, false);
2988 }
2989
2990 static int net_ads_keytab_add_update_ads(struct net_context *c,
2991                                          int argc,
2992                                          const char **argv)
2993 {
2994         return net_ads_keytab_add(c, argc, argv, true);
2995 }
2996
2997 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2998 {
2999         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3000         ADS_STRUCT *ads = NULL;
3001         ADS_STATUS status;
3002         int ret = -1;
3003
3004         if (c->display_usage) {
3005                 d_printf(  "%s\n"
3006                            "net ads keytab create\n"
3007                            "    %s\n",
3008                          _("Usage:"),
3009                          _("Create new default keytab"));
3010                 TALLOC_FREE(tmp_ctx);
3011                 return -1;
3012         }
3013
3014         if (!c->opt_user_specified && c->opt_password == NULL) {
3015                 net_use_krb_machine_account(c);
3016         }
3017
3018         status = ads_startup(c, true, tmp_ctx, &ads);
3019         if (!ADS_ERR_OK(status)) {
3020                 goto out;
3021         }
3022
3023         ret = ads_keytab_create_default(ads);
3024 out:
3025         TALLOC_FREE(tmp_ctx);
3026         return ret;
3027 }
3028
3029 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
3030 {
3031         const char *keytab = NULL;
3032
3033         if (c->display_usage) {
3034                 d_printf("%s\n%s",
3035                          _("Usage:"),
3036                          _("net ads keytab list [keytab]\n"
3037                            "  List a local keytab\n"
3038                            "    keytab\tKeytab to list\n"));
3039                 return -1;
3040         }
3041
3042         if (argc >= 1) {
3043                 keytab = argv[0];
3044         }
3045
3046         return ads_keytab_list(keytab);
3047 }
3048
3049
3050 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3051 {
3052         struct functable func[] = {
3053                 {
3054                         "add",
3055                         net_ads_keytab_add_default,
3056                         NET_TRANSPORT_ADS,
3057                         N_("Add a service principal"),
3058                         N_("net ads keytab add\n"
3059                            "    Add a service principal, updates keytab file only.")
3060                 },
3061                 {
3062                         "add_update_ads",
3063                         net_ads_keytab_add_update_ads,
3064                         NET_TRANSPORT_ADS,
3065                         N_("Add a service principal"),
3066                         N_("net ads keytab add_update_ads\n"
3067                            "    Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
3068                 },
3069                 {
3070                         "create",
3071                         net_ads_keytab_create,
3072                         NET_TRANSPORT_ADS,
3073                         N_("Create a fresh keytab"),
3074                         N_("net ads keytab create\n"
3075                            "    Create a fresh keytab or update existing one.")
3076                 },
3077                 {
3078                         "flush",
3079                         net_ads_keytab_flush,
3080                         NET_TRANSPORT_ADS,
3081                         N_("Remove all keytab entries"),
3082                         N_("net ads keytab flush\n"
3083                            "    Remove all keytab entries")
3084                 },
3085                 {
3086                         "list",
3087                         net_ads_keytab_list,
3088                         NET_TRANSPORT_ADS,
3089                         N_("List a keytab"),
3090                         N_("net ads keytab list\n"
3091                            "    List a keytab")
3092                 },
3093                 {NULL, NULL, 0, NULL, NULL}
3094         };
3095
3096         if (!USE_KERBEROS_KEYTAB) {
3097                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3098                     "keytab method to use keytab functions.\n"));
3099         }
3100
3101         return net_run_function(c, argc, argv, "net ads keytab", func);
3102 }
3103
3104 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3105 {
3106         int ret = -1;
3107
3108         if (c->display_usage) {
3109                 d_printf(  "%s\n"
3110                            "net ads kerberos renew\n"
3111                            "    %s\n",
3112                          _("Usage:"),
3113                          _("Renew TGT from existing credential cache"));
3114                 return -1;
3115         }
3116
3117         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3118         if (ret) {
3119                 d_printf(_("failed to renew kerberos ticket: %s\n"),
3120                         error_message(ret));
3121         }
3122         return ret;
3123 }
3124
3125 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3126                                        struct PAC_DATA_CTR **pac_data_ctr)
3127 {
3128         NTSTATUS status;
3129         int ret = -1;
3130         const char *impersonate_princ_s = NULL;
3131         const char *local_service = NULL;
3132         int i;
3133
3134         for (i=0; i<argc; i++) {
3135                 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3136                         impersonate_princ_s = get_string_param(argv[i]);
3137                         if (impersonate_princ_s == NULL) {
3138                                 return -1;
3139                         }
3140                 }
3141                 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3142                         local_service = get_string_param(argv[i]);
3143                         if (local_service == NULL) {
3144                                 return -1;
3145                         }
3146                 }
3147         }
3148
3149         if (local_service == NULL) {
3150                 local_service = talloc_asprintf(c, "%s$@%s",
3151                                                 lp_netbios_name(), lp_realm());
3152                 if (local_service == NULL) {
3153                         goto out;
3154                 }
3155         }
3156
3157         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3158
3159         status = kerberos_return_pac(c,
3160                                      c->opt_user_name,
3161                                      c->opt_password,
3162                                      0,
3163                                      NULL,
3164                                      NULL,
3165                                      NULL,
3166                                      true,
3167                                      true,
3168                                      2592000, /* one month */
3169                                      impersonate_princ_s,
3170                                      local_service,
3171                                      NULL,
3172                                      NULL,
3173                                      pac_data_ctr);
3174         if (!NT_STATUS_IS_OK(status)) {
3175                 d_printf(_("failed to query kerberos PAC: %s\n"),
3176                         nt_errstr(status));
3177                 goto out;
3178         }
3179
3180         ret = 0;
3181  out:
3182         return ret;
3183 }
3184
3185 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3186 {
3187         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3188         int i, num_buffers;
3189         int ret = -1;
3190         enum PAC_TYPE type = 0;
3191
3192         if (c->display_usage) {
3193                 d_printf(  "%s\n"
3194                            "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3195                            "    %s\n",
3196                          _("Usage:"),
3197                          _("Dump the Kerberos PAC"));
3198                 return -1;
3199         }
3200
3201         for (i=0; i<argc; i++) {
3202                 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3203                         type = get_int_param(argv[i]);
3204                 }
3205         }
3206
3207         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3208         if (ret) {
3209                 return ret;
3210         }
3211
3212         if (type == 0) {
3213
3214                 char *s = NULL;
3215
3216                 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3217                         pac_data_ctr->pac_data);
3218                 if (s != NULL) {
3219                         d_printf(_("The Pac: %s\n"), s);
3220                         talloc_free(s);
3221                 }
3222
3223                 return 0;
3224         }
3225
3226         num_buffers = pac_data_ctr->pac_data->num_buffers;
3227
3228         for (i=0; i<num_buffers; i++) {
3229
3230                 char *s = NULL;
3231
3232                 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3233                         continue;
3234                 }
3235
3236                 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3237                                 pac_data_ctr->pac_data->buffers[i].info);
3238                 if (s != NULL) {
3239                         d_printf(_("The Pac: %s\n"), s);
3240                         talloc_free(s);
3241                 }
3242                 break;
3243         }
3244
3245         return 0;
3246 }
3247
3248 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3249 {
3250         struct PAC_DATA_CTR *pac_data_ctr = NULL;
3251         char *filename = NULL;
3252         int ret = -1;
3253         int i;
3254
3255         if (c->display_usage) {
3256                 d_printf(  "%s\n"
3257                            "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3258                            "    %s\n",
3259                          _("Usage:"),
3260                          _("Save the Kerberos PAC"));
3261                 return -1;
3262         }
3263
3264         for (i=0; i<argc; i++) {
3265                 if (strnequal(argv[i], "filename", strlen("filename"))) {
3266                         filename = get_string_param(argv[i]);
3267                         if (filename == NULL) {
3268                                 return -1;
3269                         }
3270                 }
3271         }
3272
3273         ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3274         if (ret) {
3275                 return ret;
3276         }
3277
3278         if (filename == NULL) {
3279                 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3280                 return -1;
3281         }
3282
3283         /* save the raw format */
3284         if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3285                 d_printf(_("failed to save PAC in %s\n"), filename);
3286                 return -1;
3287         }
3288
3289         return 0;
3290 }
3291
3292 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3293 {
3294         struct functable func[] = {
3295                 {
3296                         "dump",
3297                         net_ads_kerberos_pac_dump,
3298                         NET_TRANSPORT_ADS,
3299                         N_("Dump Kerberos PAC"),
3300                         N_("net ads kerberos pac dump\n"
3301                            "    Dump a Kerberos PAC to stdout")
3302                 },
3303                 {
3304                         "save",
3305                         net_ads_kerberos_pac_save,
3306                         NET_TRANSPORT_ADS,
3307                         N_("Save Kerberos PAC"),
3308                         N_("net ads kerberos pac save\n"
3309                            "    Save a Kerberos PAC in a file")
3310                 },
3311
3312                 {NULL, NULL, 0, NULL, NULL}
3313         };
3314
3315         return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3316 }
3317
3318 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3319 {
3320         TALLOC_CTX *mem_ctx = NULL;
3321         int ret = -1;
3322         NTSTATUS status;
3323
3324         if (c->display_usage) {
3325                 d_printf(  "%s\n"
3326                            "net ads kerberos kinit\n"
3327                            "    %s\n",
3328                          _("Usage:"),
3329                          _("Get Ticket Granting Ticket (TGT) for the user"));
3330                 return -1;
3331         }
3332
3333         mem_ctx = talloc_init("net_ads_kerberos_kinit");
3334         if (!mem_ctx) {
3335                 goto out;
3336         }
3337
3338         c->opt_password = net_prompt_pass(c, c->opt_user_name);
3339
3340         ret = kerberos_kinit_password_ext(c->opt_user_name,
3341                                           c->opt_password,
3342                                           0,
3343                                           NULL,
3344                                           NULL,
3345                                           NULL,
3346                                           true,
3347                                           true,
3348                                           2592000, /* one month */
3349                                           NULL,
3350                                           NULL,
3351                                           NULL,
3352                                           &status);
3353         if (ret) {
3354                 d_printf(_("failed to kinit password: %s\n"),
3355                         nt_errstr(status));
3356         }
3357  out:
3358         return ret;
3359 }
3360
3361 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3362 {
3363         struct functable func[] = {
3364                 {
3365                         "kinit",
3366                         net_ads_kerberos_kinit,
3367                         NET_TRANSPORT_ADS,
3368                         N_("Retrieve Ticket Granting Ticket (TGT)"),
3369                         N_("net ads kerberos kinit\n"
3370                            "    Receive Ticket Granting Ticket (TGT)")
3371                 },
3372                 {
3373                         "renew",
3374                         net_ads_kerberos_renew,
3375                         NET_TRANSPORT_ADS,
3376                         N_("Renew Ticket Granting Ticket from credential cache"),
3377                         N_("net ads kerberos renew\n"
3378                            "    Renew Ticket Granting Ticket (TGT) from "
3379                            "credential cache")
3380                 },
3381                 {
3382                         "pac",
3383                         net_ads_kerberos_pac,
3384                         NET_TRANSPORT_ADS,
3385                         N_("Dump Kerberos PAC"),
3386                         N_("net ads kerberos pac\n"
3387                            "    Dump Kerberos PAC")
3388                 },
3389                 {NULL, NULL, 0, NULL, NULL}
3390         };
3391
3392         return net_run_function(c, argc, argv, "net ads kerberos", func);
3393 }
3394
3395 static int net_ads_setspn_list(struct net_context *c,
3396                                int argc,
3397                                const char **argv)
3398 {
3399         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3400         ADS_STRUCT *ads = NULL;
3401         ADS_STATUS status;
3402         bool ok = false;
3403         int ret = -1;
3404
3405         if (c->display_usage) {
3406                 d_printf("%s\n%s",
3407                          _("Usage:"),
3408                          _("net ads setspn list <machinename>\n"));
3409                 TALLOC_FREE(tmp_ctx);
3410                 return -1;
3411         }
3412
3413         status = ads_startup(c, true, tmp_ctx, &ads);
3414         if (!ADS_ERR_OK(status)) {
3415                 goto out;
3416         }
3417
3418         if (argc) {
3419                 ok = ads_setspn_list(ads, argv[0]);
3420         } else {
3421                 ok = ads_setspn_list(ads, lp_netbios_name());
3422         }
3423
3424         ret = ok ? 0 : -1;
3425 out:
3426         TALLOC_FREE(tmp_ctx);
3427         return ret;
3428 }
3429
3430 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3431 {
3432         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3433         ADS_STRUCT *ads = NULL;
3434         ADS_STATUS status;
3435         bool ok = false;
3436         int ret = -1;
3437
3438         if (c->display_usage || argc < 1) {
3439                 d_printf("%s\n%s",
3440                          _("Usage:"),
3441                          _("net ads setspn add <machinename> SPN\n"));
3442                 TALLOC_FREE(tmp_ctx);
3443                 return -1;
3444         }
3445
3446         status = ads_startup(c, true, tmp_ctx, &ads);
3447         if (!ADS_ERR_OK(status)) {
3448                 goto out;
3449         }
3450
3451         if (argc > 1) {
3452                 ok = ads_setspn_add(ads, argv[0], argv[1]);
3453         } else {
3454                 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3455         }
3456
3457         ret = ok ? 0 : -1;
3458 out:
3459         TALLOC_FREE(tmp_ctx);
3460         return ret;
3461 }
3462
3463 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3464 {
3465         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3466         ADS_STRUCT *ads = NULL;
3467         ADS_STATUS status;
3468         bool ok = false;
3469         int ret = -1;
3470
3471         if (c->display_usage || argc < 1) {
3472                 d_printf("%s\n%s",
3473                          _("Usage:"),
3474                          _("net ads setspn delete <machinename> SPN\n"));
3475                 TALLOC_FREE(tmp_ctx);
3476                 return -1;
3477         }
3478
3479         status = ads_startup(c, true, tmp_ctx, &ads);
3480         if (!ADS_ERR_OK(status)) {
3481                 goto out;
3482         }
3483
3484         if (argc > 1) {
3485                 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3486         } else {
3487                 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3488         }
3489
3490         ret = ok ? 0 : -1;
3491 out:
3492         TALLOC_FREE(tmp_ctx);
3493         return ret;
3494 }
3495
3496 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3497 {
3498         struct functable func[] = {
3499                 {
3500                         "list",
3501                         net_ads_setspn_list,
3502                         NET_TRANSPORT_ADS,
3503                         N_("List Service Principal Names (SPN)"),
3504                         N_("net ads setspn list machine\n"
3505                            "    List Service Principal Names (SPN)")
3506                 },
3507                 {
3508                         "add",
3509                         net_ads_setspn_add,
3510                         NET_TRANSPORT_ADS,
3511                         N_("Add Service Principal Names (SPN)"),
3512                         N_("net ads setspn add machine spn\n"
3513                            "    Add Service Principal Names (SPN)")
3514                 },
3515                 {
3516                         "delete",
3517                         net_ads_setspn_delete,
3518                         NET_TRANSPORT_ADS,
3519                         N_("Delete Service Principal Names (SPN)"),
3520                         N_("net ads setspn delete machine spn\n"
3521                            "    Delete Service Principal Names (SPN)")
3522                 },
3523                 {NULL, NULL, 0, NULL, NULL}
3524         };
3525
3526         return net_run_function(c, argc, argv, "net ads setspn", func);
3527 }
3528
3529 static int net_ads_enctype_lookup_account(struct net_context *c,
3530                                           ADS_STRUCT *ads,
3531                                           const char *account,
3532                                           LDAPMessage **res,
3533                                           const char **enctype_str)
3534 {
3535         const char *filter;
3536         const char *attrs[] = {
3537                 "msDS-SupportedEncryptionTypes",
3538                 NULL
3539         };
3540         int count;
3541         int ret = -1;
3542         ADS_STATUS status;
3543
3544         filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3545                                  account);
3546         if (filter == NULL) {
3547                 goto done;
3548         }
3549
3550         status = ads_search(ads, res, filter, attrs);
3551         if (!ADS_ERR_OK(status)) {
3552                 d_printf(_("no account found with filter: %s\n"), filter);
3553                 goto done;
3554         }
3555
3556         count = ads_count_replies(ads, *res);
3557         switch (count) {
3558         case 1:
3559                 break;
3560         case 0:
3561                 d_printf(_("no account found with filter: %s\n"), filter);
3562                 goto done;
3563         default:
3564                 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3565                 goto done;
3566         }
3567
3568         if (enctype_str) {
3569                 *enctype_str = ads_pull_string(ads, c, *res,
3570                                                "msDS-SupportedEncryptionTypes");
3571                 if (*enctype_str == NULL) {
3572                         d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3573                         goto done;
3574                 }
3575         }
3576
3577         ret = 0;
3578  done:
3579         return ret;
3580 }
3581
3582 static void net_ads_enctype_dump_enctypes(const char *username,
3583                                           const char *enctype_str)
3584 {
3585         int enctypes = atoi(enctype_str);
3586
3587         d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3588                 username, enctypes, enctypes);
3589
3590         printf("[%s] 0x%08x DES-CBC-CRC\n",
3591                 enctypes & ENC_CRC32 ? "X" : " ",
3592                 ENC_CRC32);
3593         printf("[%s] 0x%08x DES-CBC-MD5\n",
3594                 enctypes & ENC_RSA_MD5 ? "X" : " ",
3595                 ENC_RSA_MD5);
3596         printf("[%s] 0x%08x RC4-HMAC\n",
3597                 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3598                 ENC_RC4_HMAC_MD5);
3599         printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3600                 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3601                 ENC_HMAC_SHA1_96_AES128);
3602         printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3603                 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3604                 ENC_HMAC_SHA1_96_AES256);
3605 }
3606
3607 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3608 {
3609         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3610         ADS_STATUS status;
3611         ADS_STRUCT *ads = NULL;
3612         LDAPMessage *res = NULL;
3613         const char *str = NULL;
3614         int ret = -1;
3615
3616         if (c->display_usage || (argc < 1)) {
3617                 d_printf(  "%s\n"
3618                            "net ads enctypes list\n"
3619                            "    %s\n",
3620                          _("Usage:"),
3621                          _("List supported enctypes"));
3622                 TALLOC_FREE(tmp_ctx);
3623                 return -1;
3624         }
3625
3626         status = ads_startup(c, false, tmp_ctx, &ads);
3627         if (!ADS_ERR_OK(status)) {
3628                 goto out;
3629         }
3630
3631         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3632         if (ret) {
3633                 goto out;
3634         }
3635
3636         net_ads_enctype_dump_enctypes(argv[0], str);
3637
3638         ret = 0;
3639  out:
3640         ads_msgfree(ads, res);
3641         TALLOC_FREE(tmp_ctx);
3642         return ret;
3643 }
3644
3645 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3646 {
3647         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3648         int ret = -1;
3649         ADS_STATUS status;
3650         ADS_STRUCT *ads = NULL;
3651         LDAPMessage *res = NULL;
3652         const char *etype_list_str = NULL;
3653         const char *dn = NULL;
3654         ADS_MODLIST mods = NULL;
3655         uint32_t etype_list;
3656         const char *str = NULL;
3657
3658         if (c->display_usage || argc < 1) {
3659                 d_printf(  "%s\n"
3660                            "net ads enctypes set <sAMAccountName> [enctypes]\n"
3661                            "    %s\n",
3662                          _("Usage:"),
3663                          _("Set supported enctypes"));
3664                 TALLOC_FREE(tmp_ctx);
3665                 return -1;
3666         }
3667
3668         status = ads_startup(c, false, tmp_ctx, &ads);
3669         if (!ADS_ERR_OK(status)) {
3670                 goto done;
3671         }
3672
3673         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3674         if (ret) {
3675                 goto done;
3676         }
3677
3678         dn = ads_get_dn(ads, tmp_ctx, res);
3679         if (dn == NULL) {
3680                 goto done;
3681         }
3682
3683         etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3684 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3685         etype_list |= ENC_HMAC_SHA1_96_AES128;
3686 #endif
3687 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3688         etype_list |= ENC_HMAC_SHA1_96_AES256;
3689 #endif
3690
3691         if (argv[1] != NULL) {
3692                 sscanf(argv[1], "%i", &etype_list);
3693         }
3694
3695         etype_list_str = talloc_asprintf(tmp_ctx, "%d", etype_list);
3696         if (!etype_list_str) {
3697                 goto done;
3698         }
3699
3700         mods = ads_init_mods(tmp_ctx);
3701         if (!mods) {
3702                 goto done;
3703         }
3704
3705         status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes",
3706                              etype_list_str);
3707         if (!ADS_ERR_OK(status)) {
3708                 goto done;
3709         }
3710
3711         status = ads_gen_mod(ads, dn, mods);
3712         if (!ADS_ERR_OK(status)) {
3713                 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3714                         ads_errstr(status));
3715                 goto done;
3716         }
3717
3718         ads_msgfree(ads, res);
3719         res = NULL;
3720
3721         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3722         if (ret) {
3723                 goto done;
3724         }
3725
3726         net_ads_enctype_dump_enctypes(argv[0], str);
3727
3728         ret = 0;
3729  done:
3730         ads_msgfree(ads, res);
3731         TALLOC_FREE(tmp_ctx);
3732         return ret;
3733 }
3734
3735 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3736 {
3737         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3738         int ret = -1;
3739         ADS_STATUS status;
3740         ADS_STRUCT *ads = NULL;
3741         LDAPMessage *res = NULL;
3742         const char *dn = NULL;
3743         ADS_MODLIST mods = NULL;
3744
3745         if (c->display_usage || argc < 1) {
3746                 d_printf(  "%s\n"
3747                            "net ads enctypes delete <sAMAccountName>\n"
3748                            "    %s\n",
3749                          _("Usage:"),
3750                          _("Delete supported enctypes"));
3751                 TALLOC_FREE(tmp_ctx);
3752                 return -1;
3753         }
3754
3755         status = ads_startup(c, false, tmp_ctx, &ads);
3756         if (!ADS_ERR_OK(status)) {
3757                 goto done;
3758         }
3759
3760         ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3761         if (ret) {
3762                 goto done;
3763         }
3764
3765         dn = ads_get_dn(ads, tmp_ctx, res);
3766         if (dn == NULL) {
3767                 goto done;
3768         }
3769
3770         mods = ads_init_mods(tmp_ctx);
3771         if (!mods) {
3772                 goto done;
3773         }
3774
3775         status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes", NULL);
3776         if (!ADS_ERR_OK(status)) {
3777                 goto done;
3778         }
3779
3780         status = ads_gen_mod(ads, dn, mods);
3781         if (!ADS_ERR_OK(status)) {
3782                 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3783                         ads_errstr(status));
3784                 goto done;
3785         }
3786
3787         ret = 0;
3788
3789  done:
3790         ads_msgfree(ads, res);
3791         TALLOC_FREE(tmp_ctx);
3792         return ret;
3793 }
3794
3795 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3796 {
3797         struct functable func[] = {
3798                 {
3799                         "list",
3800                         net_ads_enctypes_list,
3801                         NET_TRANSPORT_ADS,
3802                         N_("List the supported encryption types"),
3803                         N_("net ads enctypes list\n"
3804                            "    List the supported encryption types")
3805                 },
3806                 {
3807                         "set",
3808                         net_ads_enctypes_set,
3809                         NET_TRANSPORT_ADS,
3810                         N_("Set the supported encryption types"),
3811                         N_("net ads enctypes set\n"
3812                            "    Set the supported encryption types")
3813                 },
3814                 {
3815                         "delete",
3816                         net_ads_enctypes_delete,
3817                         NET_TRANSPORT_ADS,
3818                         N_("Delete the supported encryption types"),
3819                         N_("net ads enctypes delete\n"
3820                            "    Delete the supported encryption types")
3821                 },
3822
3823                 {NULL, NULL, 0, NULL, NULL}
3824         };
3825
3826         return net_run_function(c, argc, argv, "net ads enctypes", func);
3827 }
3828
3829
3830 int net_ads(struct net_context *c, int argc, const char **argv)
3831 {
3832         struct functable func[] = {
3833                 {
3834                         "info",
3835                         net_ads_info,
3836                         NET_TRANSPORT_ADS,
3837                         N_("Display details on remote ADS server"),
3838                         N_("net ads info\n"
3839                            "    Display details on remote ADS server")
3840                 },
3841                 {
3842                         "join",
3843                         net_ads_join,
3844                         NET_TRANSPORT_ADS,
3845                         N_("Join the local machine to ADS realm"),
3846                         N_("net ads join\n"
3847                            "    Join the local machine to ADS realm")
3848                 },
3849                 {
3850                         "testjoin",
3851                         net_ads_testjoin,
3852                         NET_TRANSPORT_ADS,
3853                         N_("Validate machine account"),
3854                         N_("net ads testjoin\n"
3855                            "    Validate machine account")
3856                 },
3857                 {
3858                         "leave",
3859                         net_ads_leave,
3860                         NET_TRANSPORT_ADS,
3861                         N_("Remove the local machine from ADS"),
3862                         N_("net ads leave\n"
3863                            "    Remove the local machine from ADS")
3864                 },
3865                 {
3866                         "status",
3867                         net_ads_status,
3868                         NET_TRANSPORT_ADS,
3869                         N_("Display machine account details"),
3870                         N_("net ads status\n"
3871                            "    Display machine account details")
3872                 },
3873                 {
3874                         "user",
3875                         net_ads_user,
3876                         NET_TRANSPORT_ADS,
3877                         N_("List/modify users"),
3878                         N_("net ads user\n"
3879                            "    List/modify users")
3880                 },
3881                 {
3882                         "group",
3883                         net_ads_group,
3884                         NET_TRANSPORT_ADS,
3885                         N_("List/modify groups"),
3886                         N_("net ads group\n"
3887                            "    List/modify groups")
3888                 },
3889                 {
3890                         "dns",
3891                         net_ads_dns,
3892                         NET_TRANSPORT_ADS,
3893                         N_("Issue dynamic DNS update"),
3894                         N_("net ads dns\n"
3895                            "    Issue dynamic DNS update")
3896                 },
3897                 {
3898                         "password",
3899                         net_ads_password,
3900                         NET_TRANSPORT_ADS,
3901                         N_("Change user passwords"),
3902                         N_("net ads password\n"
3903                            "    Change user passwords")
3904                 },
3905                 {
3906                         "changetrustpw",
3907                         net_ads_changetrustpw,
3908                         NET_TRANSPORT_ADS,
3909                         N_("Change trust account password"),
3910                         N_("net ads changetrustpw\n"
3911                            "    Change trust account password")
3912                 },
3913                 {
3914                         "printer",
3915                         net_ads_printer,
3916                         NET_TRANSPORT_ADS,
3917                         N_("List/modify printer entries"),
3918                         N_("net ads printer\n"
3919                            "    List/modify printer entries")
3920                 },
3921                 {
3922                         "search",
3923                         net_ads_search,
3924                         NET_TRANSPORT_ADS,
3925                         N_("Issue LDAP search using filter"),
3926                         N_("net ads search\n"
3927                            "    Issue LDAP search using filter")
3928                 },
3929                 {
3930                         "dn",
3931                         net_ads_dn,
3932                         NET_TRANSPORT_ADS,
3933                         N_("Issue LDAP search by DN"),
3934                         N_("net ads dn\n"
3935                            "    Issue LDAP search by DN")
3936                 },
3937                 {
3938                         "sid",
3939                         net_ads_sid,
3940                         NET_TRANSPORT_ADS,
3941                         N_("Issue LDAP search by SID"),
3942                         N_("net ads sid\n"
3943                            "    Issue LDAP search by SID")
3944                 },
3945                 {
3946                         "workgroup",
3947                         net_ads_workgroup,
3948                         NET_TRANSPORT_ADS,
3949                         N_("Display workgroup name"),
3950                         N_("net ads workgroup\n"
3951                            "    Display the workgroup name")
3952                 },
3953                 {
3954                         "lookup",
3955                         net_ads_lookup,
3956                         NET_TRANSPORT_ADS,
3957                         N_("Perform CLDAP query on DC"),
3958                         N_("net ads lookup\n"
3959                            "    Find the ADS DC using CLDAP lookups")
3960                 },
3961                 {
3962                         "keytab",
3963                         net_ads_keytab,
3964                         NET_TRANSPORT_ADS,
3965                         N_("Manage local keytab file"),
3966                         N_("net ads keytab\n"
3967                            "    Manage local keytab file")
3968                 },
3969                 {
3970                         "setspn",
3971                         net_ads_setspn,
3972                         NET_TRANSPORT_ADS,
3973                         N_("Manage Service Principal Names (SPN)s"),
3974                         N_("net ads spnset\n"
3975                            "    Manage Service Principal Names (SPN)s")
3976                 },
3977                 {
3978                         "gpo",
3979                         net_ads_gpo,
3980                         NET_TRANSPORT_ADS,
3981                         N_("Manage group policy objects"),
3982                         N_("net ads gpo\n"
3983                            "    Manage group policy objects")
3984                 },
3985                 {
3986                         "kerberos",
3987                         net_ads_kerberos,
3988                         NET_TRANSPORT_ADS,
3989                         N_("Manage kerberos keytab"),
3990                         N_("net ads kerberos\n"
3991                            "    Manage kerberos keytab")
3992                 },
3993                 {
3994                         "enctypes",
3995                         net_ads_enctypes,
3996                         NET_TRANSPORT_ADS,
3997                         N_("List/modify supported encryption types"),
3998                         N_("net ads enctypes\n"
3999                            "    List/modify enctypes")
4000                 },
4001                 {NULL, NULL, 0, NULL, NULL}
4002         };
4003
4004         return net_run_function(c, argc, argv, "net ads", func);
4005 }
4006
4007 #else
4008
4009 static int net_ads_noads(void)
4010 {
4011         d_fprintf(stderr, _("ADS support not compiled in\n"));
4012         return -1;
4013 }
4014
4015 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
4016 {
4017         return net_ads_noads();
4018 }
4019
4020 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
4021 {
4022         return net_ads_noads();
4023 }
4024
4025 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
4026 {
4027         return net_ads_noads();
4028 }
4029
4030 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
4031 {
4032         return net_ads_noads();
4033 }
4034
4035 int net_ads_join(struct net_context *c, int argc, const char **argv)
4036 {
4037         return net_ads_noads();
4038 }
4039
4040 int net_ads_user(struct net_context *c, int argc, const char **argv)
4041 {
4042         return net_ads_noads();
4043 }
4044
4045 int net_ads_group(struct net_context *c, int argc, const char **argv)
4046 {
4047         return net_ads_noads();
4048 }
4049
4050 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
4051 {
4052         return net_ads_noads();
4053 }
4054
4055 /* this one shouldn't display a message */
4056 int net_ads_check(struct net_context *c)
4057 {
4058         return -1;
4059 }
4060
4061 int net_ads_check_our_domain(struct net_context *c)
4062 {
4063         return -1;
4064 }
4065
4066 int net_ads(struct net_context *c, int argc, const char **argv)
4067 {
4068         return net_ads_noads();
4069 }
4070
4071 #endif  /* HAVE_ADS */