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