f133eec0fc19b5150d9c19a7fe0ed1c1db54b2ef
[ira/wip.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 "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
28
29 #ifdef HAVE_ADS
30
31 /* when we do not have sufficient input parameters to contact a remote domain
32  * we always fall back to our own realm - Guenther*/
33
34 static const char *assume_own_realm(struct net_context *c)
35 {
36         if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
37                 return lp_realm();
38         }
39
40         return NULL;
41 }
42
43 /*
44   do a cldap netlogon query
45 */
46 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
47 {
48         char addr[INET6_ADDRSTRLEN];
49         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
50
51         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
52         if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
53                 d_fprintf(stderr, _("CLDAP query failed!\n"));
54                 return -1;
55         }
56
57         d_printf(_("Information for Domain Controller: %s\n\n"),
58                 addr);
59
60         d_printf(_("Response Type: "));
61         switch (reply.command) {
62         case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
63                 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
64                 break;
65         case LOGON_SAM_LOGON_RESPONSE_EX:
66                 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
67                 break;
68         default:
69                 d_printf("0x%x\n", reply.command);
70                 break;
71         }
72
73         d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
74
75         d_printf(_("Flags:\n"
76                    "\tIs a PDC:                                   %s\n"
77                    "\tIs a GC of the forest:                      %s\n"
78                    "\tIs an LDAP server:                          %s\n"
79                    "\tSupports DS:                                %s\n"
80                    "\tIs running a KDC:                           %s\n"
81                    "\tIs running time services:                   %s\n"
82                    "\tIs the closest DC:                          %s\n"
83                    "\tIs writable:                                %s\n"
84                    "\tHas a hardware clock:                       %s\n"
85                    "\tIs a non-domain NC serviced by LDAP server: %s\n"
86                    "\tIs NT6 DC that has some secrets:            %s\n"
87                    "\tIs NT6 DC that has all secrets:             %s\n"),
88                    (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
89                    (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
90                    (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
91                    (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
92                    (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
93                    (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
94                    (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
95                    (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
96                    (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
97                    (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
98                    (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
99                    (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
100
101
102         printf(_("Forest:\t\t\t%s\n"), reply.forest);
103         printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
104         printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
105
106         printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
107         printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
108
109         if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
110
111         printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
112         printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
113
114         d_printf(_("NT Version: %d\n"), reply.nt_version);
115         d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
116         d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
117
118         return 0;
119 }
120
121 /*
122   this implements the CLDAP based netlogon lookup requests
123   for finding the domain controller of a ADS domain
124 */
125 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
126 {
127         ADS_STRUCT *ads;
128         int ret;
129
130         if (c->display_usage) {
131                 d_printf(_("Usage:\n"
132                            "net ads lookup\n"
133                            "    Find the ADS DC using CLDAP lookup.\n"));
134                 return 0;
135         }
136
137         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
138                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
139                 ads_destroy(&ads);
140                 return -1;
141         }
142
143         if (!ads->config.realm) {
144                 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
145                 ads->ldap.port = 389;
146         }
147
148         ret = net_ads_cldap_netlogon(c, ads);
149         ads_destroy(&ads);
150         return ret;
151 }
152
153
154
155 static int net_ads_info(struct net_context *c, int argc, const char **argv)
156 {
157         ADS_STRUCT *ads;
158         char addr[INET6_ADDRSTRLEN];
159
160         if (c->display_usage) {
161                 d_printf(_("Usage:\n"
162                            "net ads info\n"
163                            "    Display information about an Active Directory "
164                            "server.\n"));
165                 return 0;
166         }
167
168         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
169                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
170                 return -1;
171         }
172
173         if (!ads || !ads->config.realm) {
174                 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
175                 ads_destroy(&ads);
176                 return -1;
177         }
178
179         /* Try to set the server's current time since we didn't do a full
180            TCP LDAP session initially */
181
182         if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
183                 d_fprintf( stderr, _("Failed to get server's current time!\n"));
184         }
185
186         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
187
188         d_printf(_("LDAP server: %s\n"), addr);
189         d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
190         d_printf(_("Realm: %s\n"), ads->config.realm);
191         d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
192         d_printf(_("LDAP port: %d\n"), ads->ldap.port);
193         d_printf(_("Server time: %s\n"),
194                          http_timestring(talloc_tos(), ads->config.current_time));
195
196         d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
197         d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
198
199         ads_destroy(&ads);
200         return 0;
201 }
202
203 static void use_in_memory_ccache(void) {
204         /* Use in-memory credentials cache so we do not interfere with
205          * existing credentials */
206         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
207 }
208
209 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
210                                   uint32 auth_flags, ADS_STRUCT **ads_ret)
211 {
212         ADS_STRUCT *ads = NULL;
213         ADS_STATUS status;
214         bool need_password = false;
215         bool second_time = false;
216         char *cp;
217         const char *realm = NULL;
218         bool tried_closest_dc = false;
219
220         /* lp_realm() should be handled by a command line param,
221            However, the join requires that realm be set in smb.conf
222            and compares our realm with the remote server's so this is
223            ok until someone needs more flexibility */
224
225         *ads_ret = NULL;
226
227 retry_connect:
228         if (only_own_domain) {
229                 realm = lp_realm();
230         } else {
231                 realm = assume_own_realm(c);
232         }
233
234         ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
235
236         if (!c->opt_user_name) {
237                 c->opt_user_name = "administrator";
238         }
239
240         if (c->opt_user_specified) {
241                 need_password = true;
242         }
243
244 retry:
245         if (!c->opt_password && need_password && !c->opt_machine_pass) {
246                 c->opt_password = net_prompt_pass(c, c->opt_user_name);
247                 if (!c->opt_password) {
248                         ads_destroy(&ads);
249                         return ADS_ERROR(LDAP_NO_MEMORY);
250                 }
251         }
252
253         if (c->opt_password) {
254                 use_in_memory_ccache();
255                 SAFE_FREE(ads->auth.password);
256                 ads->auth.password = smb_xstrdup(c->opt_password);
257         }
258
259         ads->auth.flags |= auth_flags;
260         SAFE_FREE(ads->auth.user_name);
261         ads->auth.user_name = smb_xstrdup(c->opt_user_name);
262
263        /*
264         * If the username is of the form "name@realm",
265         * extract the realm and convert to upper case.
266         * This is only used to establish the connection.
267         */
268        if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
269                 *cp++ = '\0';
270                 SAFE_FREE(ads->auth.realm);
271                 ads->auth.realm = smb_xstrdup(cp);
272                 strupper_m(ads->auth.realm);
273        }
274
275         status = ads_connect(ads);
276
277         if (!ADS_ERR_OK(status)) {
278
279                 if (NT_STATUS_EQUAL(ads_ntstatus(status),
280                                     NT_STATUS_NO_LOGON_SERVERS)) {
281                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
282                         ads_destroy(&ads);
283                         return status;
284                 }
285
286                 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
287                         need_password = true;
288                         second_time = true;
289                         goto retry;
290                 } else {
291                         ads_destroy(&ads);
292                         return status;
293                 }
294         }
295
296         /* when contacting our own domain, make sure we use the closest DC.
297          * This is done by reconnecting to ADS because only the first call to
298          * ads_connect will give us our own sitename */
299
300         if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
301
302                 tried_closest_dc = true; /* avoid loop */
303
304                 if (!ads_closest_dc(ads)) {
305
306                         namecache_delete(ads->server.realm, 0x1C);
307                         namecache_delete(ads->server.workgroup, 0x1C);
308
309                         ads_destroy(&ads);
310                         ads = NULL;
311
312                         goto retry_connect;
313                 }
314         }
315
316         *ads_ret = ads;
317         return status;
318 }
319
320 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
321 {
322         return ads_startup_int(c, only_own_domain, 0, ads);
323 }
324
325 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
326 {
327         return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
328 }
329
330 /*
331   Check to see if connection can be made via ads.
332   ads_startup() stores the password in opt_password if it needs to so
333   that rpc or rap can use it without re-prompting.
334 */
335 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
336 {
337         ADS_STRUCT *ads;
338         ADS_STATUS status;
339
340         if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
341                 return -1;
342         }
343
344         ads->auth.flags |= ADS_AUTH_NO_BIND;
345
346         status = ads_connect(ads);
347         if ( !ADS_ERR_OK(status) ) {
348                 return -1;
349         }
350
351         ads_destroy(&ads);
352         return 0;
353 }
354
355 int net_ads_check_our_domain(struct net_context *c)
356 {
357         return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
358 }
359
360 int net_ads_check(struct net_context *c)
361 {
362         return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
363 }
364
365 /*
366    determine the netbios workgroup name for a domain
367  */
368 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
369 {
370         ADS_STRUCT *ads;
371         char addr[INET6_ADDRSTRLEN];
372         struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
373
374         if (c->display_usage) {
375                 d_printf(_("Usage:\n"
376                            "net ads workgroup\n"
377                            "    Print the workgroup name\n"));
378                 return 0;
379         }
380
381         if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
382                 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
383                 return -1;
384         }
385
386         if (!ads->config.realm) {
387                 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
388                 ads->ldap.port = 389;
389         }
390
391         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
392         if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
393                 d_fprintf(stderr, _("CLDAP query failed!\n"));
394                 ads_destroy(&ads);
395                 return -1;
396         }
397
398         d_printf(_("Workgroup: %s\n"), reply.domain);
399
400         ads_destroy(&ads);
401
402         return 0;
403 }
404
405
406
407 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
408 {
409         char **disp_fields = (char **) data_area;
410
411         if (!field) { /* must be end of record */
412                 if (disp_fields[0]) {
413                         if (!strchr_m(disp_fields[0], '$')) {
414                                 if (disp_fields[1])
415                                         d_printf("%-21.21s %s\n",
416                                                disp_fields[0], disp_fields[1]);
417                                 else
418                                         d_printf("%s\n", disp_fields[0]);
419                         }
420                 }
421                 SAFE_FREE(disp_fields[0]);
422                 SAFE_FREE(disp_fields[1]);
423                 return true;
424         }
425         if (!values) /* must be new field, indicate string field */
426                 return true;
427         if (StrCaseCmp(field, "sAMAccountName") == 0) {
428                 disp_fields[0] = SMB_STRDUP((char *) values[0]);
429         }
430         if (StrCaseCmp(field, "description") == 0)
431                 disp_fields[1] = SMB_STRDUP((char *) values[0]);
432         return true;
433 }
434
435 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
436 {
437         return net_user_usage(c, argc, argv);
438 }
439
440 static int ads_user_add(struct net_context *c, int argc, const char **argv)
441 {
442         ADS_STRUCT *ads;
443         ADS_STATUS status;
444         char *upn, *userdn;
445         LDAPMessage *res=NULL;
446         int rc = -1;
447         char *ou_str = NULL;
448
449         if (argc < 1 || c->display_usage)
450                 return net_ads_user_usage(c, argc, argv);
451
452         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
453                 return -1;
454         }
455
456         status = ads_find_user_acct(ads, &res, argv[0]);
457
458         if (!ADS_ERR_OK(status)) {
459                 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
460                 goto done;
461         }
462
463         if (ads_count_replies(ads, res)) {
464                 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
465                           argv[0]);
466                 goto done;
467         }
468
469         if (c->opt_container) {
470                 ou_str = SMB_STRDUP(c->opt_container);
471         } else {
472                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
473         }
474
475         status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
476
477         if (!ADS_ERR_OK(status)) {
478                 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
479                          ads_errstr(status));
480                 goto done;
481         }
482
483         /* if no password is to be set, we're done */
484         if (argc == 1) {
485                 d_printf(_("User %s added\n"), argv[0]);
486                 rc = 0;
487                 goto done;
488         }
489
490         /* try setting the password */
491         if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
492                 goto done;
493         }
494         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
495                                        ads->auth.time_offset);
496         SAFE_FREE(upn);
497         if (ADS_ERR_OK(status)) {
498                 d_printf(_("User %s added\n"), argv[0]);
499                 rc = 0;
500                 goto done;
501         }
502
503         /* password didn't set, delete account */
504         d_fprintf(stderr, _("Could not add user %s. "
505                             "Error setting password %s\n"),
506                  argv[0], ads_errstr(status));
507         ads_msgfree(ads, res);
508         status=ads_find_user_acct(ads, &res, argv[0]);
509         if (ADS_ERR_OK(status)) {
510                 userdn = ads_get_dn(ads, talloc_tos(), res);
511                 ads_del_dn(ads, userdn);
512                 TALLOC_FREE(userdn);
513         }
514
515  done:
516         if (res)
517                 ads_msgfree(ads, res);
518         ads_destroy(&ads);
519         SAFE_FREE(ou_str);
520         return rc;
521 }
522
523 static int ads_user_info(struct net_context *c, int argc, const char **argv)
524 {
525         ADS_STRUCT *ads = NULL;
526         ADS_STATUS rc;
527         LDAPMessage *res = NULL;
528         TALLOC_CTX *frame;
529         int ret = 0;
530         wbcErr wbc_status;
531         const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
532         char *searchstring=NULL;
533         char **grouplist;
534         char *primary_group;
535         char *escaped_user;
536         DOM_SID primary_group_sid;
537         uint32_t group_rid;
538         enum SID_NAME_USE type;
539
540         if (argc < 1 || c->display_usage) {
541                 return net_ads_user_usage(c, argc, argv);
542         }
543
544         frame = talloc_new(talloc_tos());
545         if (frame == NULL) {
546                 return -1;
547         }
548
549         escaped_user = escape_ldap_string(frame, argv[0]);
550         if (!escaped_user) {
551                 d_fprintf(stderr,
552                           _("ads_user_info: failed to escape user %s\n"),
553                           argv[0]);
554                 return -1;
555         }
556
557         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
558                 ret = -1;
559                 goto error;
560         }
561
562         if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
563                 ret =-1;
564                 goto error;
565         }
566         rc = ads_search(ads, &res, searchstring, attrs);
567         SAFE_FREE(searchstring);
568
569         if (!ADS_ERR_OK(rc)) {
570                 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
571                 ret = -1;
572                 goto error;
573         }
574
575         if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
576                 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
577                 ret = -1;
578                 goto error;
579         }
580
581         rc = ads_domain_sid(ads, &primary_group_sid);
582         if (!ADS_ERR_OK(rc)) {
583                 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
584                 ret = -1;
585                 goto error;
586         }
587
588         sid_append_rid(&primary_group_sid, group_rid);
589
590         wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
591                                   NULL, /* don't look up domain */
592                                   &primary_group,
593                                   (enum wbcSidType *) &type);
594         if (!WBC_ERROR_IS_OK(wbc_status)) {
595                 d_fprintf(stderr, "wbcLookupSid: %s\n",
596                           wbcErrorString(wbc_status));
597                 ret = -1;
598                 goto error;
599         }
600
601         d_printf("%s\n", primary_group);
602
603         wbcFreeMemory(primary_group);
604
605         grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
606                                     (LDAPMessage *)res, "memberOf");
607
608         if (grouplist) {
609                 int i;
610                 char **groupname;
611                 for (i=0;grouplist[i];i++) {
612                         groupname = ldap_explode_dn(grouplist[i], 1);
613                         d_printf("%s\n", groupname[0]);
614                         ldap_value_free(groupname);
615                 }
616                 ldap_value_free(grouplist);
617         }
618
619 error:
620         if (res) ads_msgfree(ads, res);
621         if (ads) ads_destroy(&ads);
622         TALLOC_FREE(frame);
623         return ret;
624 }
625
626 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
627 {
628         ADS_STRUCT *ads;
629         ADS_STATUS rc;
630         LDAPMessage *res = NULL;
631         char *userdn;
632
633         if (argc < 1) {
634                 return net_ads_user_usage(c, argc, argv);
635         }
636
637         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
638                 return -1;
639         }
640
641         rc = ads_find_user_acct(ads, &res, argv[0]);
642         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
643                 d_printf(_("User %s does not exist.\n"), argv[0]);
644                 ads_msgfree(ads, res);
645                 ads_destroy(&ads);
646                 return -1;
647         }
648         userdn = ads_get_dn(ads, talloc_tos(), res);
649         ads_msgfree(ads, res);
650         rc = ads_del_dn(ads, userdn);
651         TALLOC_FREE(userdn);
652         if (ADS_ERR_OK(rc)) {
653                 d_printf(_("User %s deleted\n"), argv[0]);
654                 ads_destroy(&ads);
655                 return 0;
656         }
657         d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
658                  ads_errstr(rc));
659         ads_destroy(&ads);
660         return -1;
661 }
662
663 int net_ads_user(struct net_context *c, int argc, const char **argv)
664 {
665         struct functable func[] = {
666                 {
667                         "add",
668                         ads_user_add,
669                         NET_TRANSPORT_ADS,
670                         N_("Add an AD user"),
671                         N_("net ads user add\n"
672                            "    Add an AD user")
673                 },
674                 {
675                         "info",
676                         ads_user_info,
677                         NET_TRANSPORT_ADS,
678                         N_("Display information about an AD user"),
679                         N_("net ads user info\n"
680                            "    Display information about an AD user")
681                 },
682                 {
683                         "delete",
684                         ads_user_delete,
685                         NET_TRANSPORT_ADS,
686                         N_("Delete an AD user"),
687                         N_("net ads user delete\n"
688                            "    Delete an AD user")
689                 },
690                 {NULL, NULL, 0, NULL, NULL}
691         };
692         ADS_STRUCT *ads;
693         ADS_STATUS rc;
694         const char *shortattrs[] = {"sAMAccountName", NULL};
695         const char *longattrs[] = {"sAMAccountName", "description", NULL};
696         char *disp_fields[2] = {NULL, NULL};
697
698         if (argc == 0) {
699                 if (c->display_usage) {
700                         d_printf(_("Usage:\n"
701                                    "net ads user\n"
702                                    "    List AD users\n"));
703                         net_display_usage_from_functable(func);
704                         return 0;
705                 }
706
707                 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
708                         return -1;
709                 }
710
711                 if (c->opt_long_list_entries)
712                         d_printf(_("\nUser name             Comment"
713                                    "\n-----------------------------\n"));
714
715                 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
716                                           LDAP_SCOPE_SUBTREE,
717                                           "(objectCategory=user)",
718                                           c->opt_long_list_entries ? longattrs :
719                                           shortattrs, usergrp_display,
720                                           disp_fields);
721                 ads_destroy(&ads);
722                 return ADS_ERR_OK(rc) ? 0 : -1;
723         }
724
725         return net_run_function(c, argc, argv, "net ads user", func);
726 }
727
728 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
729 {
730         return net_group_usage(c, argc, argv);
731 }
732
733 static int ads_group_add(struct net_context *c, int argc, const char **argv)
734 {
735         ADS_STRUCT *ads;
736         ADS_STATUS status;
737         LDAPMessage *res=NULL;
738         int rc = -1;
739         char *ou_str = NULL;
740
741         if (argc < 1 || c->display_usage) {
742                 return net_ads_group_usage(c, argc, argv);
743         }
744
745         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
746                 return -1;
747         }
748
749         status = ads_find_user_acct(ads, &res, argv[0]);
750
751         if (!ADS_ERR_OK(status)) {
752                 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
753                 goto done;
754         }
755
756         if (ads_count_replies(ads, res)) {
757                 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
758                 goto done;
759         }
760
761         if (c->opt_container) {
762                 ou_str = SMB_STRDUP(c->opt_container);
763         } else {
764                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
765         }
766
767         status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
768
769         if (ADS_ERR_OK(status)) {
770                 d_printf(_("Group %s added\n"), argv[0]);
771                 rc = 0;
772         } else {
773                 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
774                          ads_errstr(status));
775         }
776
777  done:
778         if (res)
779                 ads_msgfree(ads, res);
780         ads_destroy(&ads);
781         SAFE_FREE(ou_str);
782         return rc;
783 }
784
785 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
786 {
787         ADS_STRUCT *ads;
788         ADS_STATUS rc;
789         LDAPMessage *res = NULL;
790         char *groupdn;
791
792         if (argc < 1 || c->display_usage) {
793                 return net_ads_group_usage(c, argc, argv);
794         }
795
796         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
797                 return -1;
798         }
799
800         rc = ads_find_user_acct(ads, &res, argv[0]);
801         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
802                 d_printf(_("Group %s does not exist.\n"), argv[0]);
803                 ads_msgfree(ads, res);
804                 ads_destroy(&ads);
805                 return -1;
806         }
807         groupdn = ads_get_dn(ads, talloc_tos(), res);
808         ads_msgfree(ads, res);
809         rc = ads_del_dn(ads, groupdn);
810         TALLOC_FREE(groupdn);
811         if (ADS_ERR_OK(rc)) {
812                 d_printf(_("Group %s deleted\n"), argv[0]);
813                 ads_destroy(&ads);
814                 return 0;
815         }
816         d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
817                  ads_errstr(rc));
818         ads_destroy(&ads);
819         return -1;
820 }
821
822 int net_ads_group(struct net_context *c, int argc, const char **argv)
823 {
824         struct functable func[] = {
825                 {
826                         "add",
827                         ads_group_add,
828                         NET_TRANSPORT_ADS,
829                         N_("Add an AD group"),
830                         N_("net ads group add\n"
831                            "    Add an AD group")
832                 },
833                 {
834                         "delete",
835                         ads_group_delete,
836                         NET_TRANSPORT_ADS,
837                         N_("Delete an AD group"),
838                         N_("net ads group delete\n"
839                            "    Delete an AD group")
840                 },
841                 {NULL, NULL, 0, NULL, NULL}
842         };
843         ADS_STRUCT *ads;
844         ADS_STATUS rc;
845         const char *shortattrs[] = {"sAMAccountName", NULL};
846         const char *longattrs[] = {"sAMAccountName", "description", NULL};
847         char *disp_fields[2] = {NULL, NULL};
848
849         if (argc == 0) {
850                 if (c->display_usage) {
851                         d_printf(_("Usage:\n"
852                                    "net ads group\n"
853                                    "    List AD groups\n"));
854                         net_display_usage_from_functable(func);
855                         return 0;
856                 }
857
858                 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
859                         return -1;
860                 }
861
862                 if (c->opt_long_list_entries)
863                         d_printf(_("\nGroup name            Comment"
864                                    "\n-----------------------------\n"));
865                 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
866                                           LDAP_SCOPE_SUBTREE,
867                                           "(objectCategory=group)",
868                                           c->opt_long_list_entries ? longattrs :
869                                           shortattrs, usergrp_display,
870                                           disp_fields);
871
872                 ads_destroy(&ads);
873                 return ADS_ERR_OK(rc) ? 0 : -1;
874         }
875         return net_run_function(c, argc, argv, "net ads group", func);
876 }
877
878 static int net_ads_status(struct net_context *c, int argc, const char **argv)
879 {
880         ADS_STRUCT *ads;
881         ADS_STATUS rc;
882         LDAPMessage *res;
883
884         if (c->display_usage) {
885                 d_printf(_("Usage:\n"
886                            "net ads status\n"
887                            "    Display machine account details\n"));
888                 return 0;
889         }
890
891         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
892                 return -1;
893         }
894
895         rc = ads_find_machine_acct(ads, &res, global_myname());
896         if (!ADS_ERR_OK(rc)) {
897                 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
898                 ads_destroy(&ads);
899                 return -1;
900         }
901
902         if (ads_count_replies(ads, res) == 0) {
903                 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
904                 ads_destroy(&ads);
905                 return -1;
906         }
907
908         ads_dump(ads, res);
909         ads_destroy(&ads);
910         return 0;
911 }
912
913 /*******************************************************************
914  Leave an AD domain.  Windows XP disables the machine account.
915  We'll try the same.  The old code would do an LDAP delete.
916  That only worked using the machine creds because added the machine
917  with full control to the computer object's ACL.
918 *******************************************************************/
919
920 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
921 {
922         TALLOC_CTX *ctx;
923         struct libnet_UnjoinCtx *r = NULL;
924         WERROR werr;
925
926         if (c->display_usage) {
927                 d_printf(_("Usage:\n"
928                            "net ads leave\n"
929                            "    Leave an AD domain\n"));
930                 return 0;
931         }
932
933         if (!*lp_realm()) {
934                 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
935                 return -1;
936         }
937
938         if (!(ctx = talloc_init("net_ads_leave"))) {
939                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
940                 return -1;
941         }
942
943         if (!c->opt_kerberos) {
944                 use_in_memory_ccache();
945         }
946
947         werr = libnet_init_UnjoinCtx(ctx, &r);
948         if (!W_ERROR_IS_OK(werr)) {
949                 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
950                 return -1;
951         }
952
953         r->in.debug             = true;
954         r->in.use_kerberos      = c->opt_kerberos;
955         r->in.dc_name           = c->opt_host;
956         r->in.domain_name       = lp_realm();
957         r->in.admin_account     = c->opt_user_name;
958         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
959         r->in.modify_config     = lp_config_backend_is_registry();
960
961         /* Try to delete it, but if that fails, disable it.  The
962            WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
963         r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
964                                   WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
965         r->in.delete_machine_account = true;
966
967         werr = libnet_Unjoin(ctx, r);
968         if (!W_ERROR_IS_OK(werr)) {
969                 d_printf(_("Failed to leave domain: %s\n"),
970                          r->out.error_string ? r->out.error_string :
971                          get_friendly_werror_msg(werr));
972                 goto done;
973         }
974
975         if (r->out.deleted_machine_account) {
976                 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
977                         r->in.machine_name, r->out.dns_domain_name);
978                 goto done;
979         }
980
981         /* We couldn't delete it - see if the disable succeeded. */
982         if (r->out.disabled_machine_account) {
983                 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
984                         r->in.machine_name, r->out.dns_domain_name);
985                 werr = WERR_OK;
986                 goto done;
987         }
988
989         /* Based on what we requseted, we shouldn't get here, but if
990            we did, it means the secrets were removed, and therefore
991            we have left the domain */
992         d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
993                   r->in.machine_name, r->out.dns_domain_name);
994
995  done:
996         TALLOC_FREE(r);
997         TALLOC_FREE(ctx);
998
999         if (W_ERROR_IS_OK(werr)) {
1000                 return 0;
1001         }
1002
1003         return -1;
1004 }
1005
1006 static NTSTATUS net_ads_join_ok(struct net_context *c)
1007 {
1008         ADS_STRUCT *ads = NULL;
1009         ADS_STATUS status;
1010
1011         if (!secrets_init()) {
1012                 DEBUG(1,("Failed to initialise secrets database\n"));
1013                 return NT_STATUS_ACCESS_DENIED;
1014         }
1015
1016         net_use_krb_machine_account(c);
1017
1018         status = ads_startup(c, true, &ads);
1019         if (!ADS_ERR_OK(status)) {
1020                 return ads_ntstatus(status);
1021         }
1022
1023         ads_destroy(&ads);
1024         return NT_STATUS_OK;
1025 }
1026
1027 /*
1028   check that an existing join is OK
1029  */
1030 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1031 {
1032         NTSTATUS status;
1033         use_in_memory_ccache();
1034
1035         if (c->display_usage) {
1036                 d_printf(_("Usage:\n"
1037                            "net ads testjoin\n"
1038                            "    Test if the existing join is ok\n"));
1039                 return 0;
1040         }
1041
1042         /* Display success or failure */
1043         status = net_ads_join_ok(c);
1044         if (!NT_STATUS_IS_OK(status)) {
1045                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1046                         get_friendly_nt_error_msg(status));
1047                 return -1;
1048         }
1049
1050         printf(_("Join is OK\n"));
1051         return 0;
1052 }
1053
1054 /*******************************************************************
1055   Simple configu checks before beginning the join
1056  ********************************************************************/
1057
1058 static WERROR check_ads_config( void )
1059 {
1060         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1061                 d_printf(_("Host is not configured as a member server.\n"));
1062                 return WERR_INVALID_DOMAIN_ROLE;
1063         }
1064
1065         if (strlen(global_myname()) > 15) {
1066                 d_printf(_("Our netbios name can be at most 15 chars long, "
1067                            "\"%s\" is %u chars long\n"), global_myname(),
1068                          (unsigned int)strlen(global_myname()));
1069                 return WERR_INVALID_COMPUTERNAME;
1070         }
1071
1072         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1073                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1074                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1075                 return WERR_INVALID_PARAM;
1076         }
1077
1078         return WERR_OK;
1079 }
1080
1081 /*******************************************************************
1082  Send a DNS update request
1083 *******************************************************************/
1084
1085 #if defined(WITH_DNS_UPDATES)
1086 #include "dns.h"
1087 DNS_ERROR DoDNSUpdate(char *pszServerName,
1088                       const char *pszDomainName, const char *pszHostName,
1089                       const struct sockaddr_storage *sslist,
1090                       size_t num_addrs );
1091
1092 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1093                                         const char *machine_name,
1094                                         const struct sockaddr_storage *addrs,
1095                                         int num_addrs)
1096 {
1097         struct dns_rr_ns *nameservers = NULL;
1098         int ns_count = 0;
1099         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1100         DNS_ERROR dns_err;
1101         fstring dns_server;
1102         const char *dnsdomain = NULL;
1103         char *root_domain = NULL;
1104
1105         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1106                 d_printf(_("No DNS domain configured for %s. "
1107                            "Unable to perform DNS Update.\n"), machine_name);
1108                 status = NT_STATUS_INVALID_PARAMETER;
1109                 goto done;
1110         }
1111         dnsdomain++;
1112
1113         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1114         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1115                 /* Child domains often do not have NS records.  Look
1116                    for the NS record for the forest root domain
1117                    (rootDomainNamingContext in therootDSE) */
1118
1119                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1120                 LDAPMessage *msg = NULL;
1121                 char *root_dn;
1122                 ADS_STATUS ads_status;
1123
1124                 if ( !ads->ldap.ld ) {
1125                         ads_status = ads_connect( ads );
1126                         if ( !ADS_ERR_OK(ads_status) ) {
1127                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1128                                 goto done;
1129                         }
1130                 }
1131
1132                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1133                                        "(objectclass=*)", rootname_attrs, &msg);
1134                 if (!ADS_ERR_OK(ads_status)) {
1135                         goto done;
1136                 }
1137
1138                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1139                 if ( !root_dn ) {
1140                         ads_msgfree( ads, msg );
1141                         goto done;
1142                 }
1143
1144                 root_domain = ads_build_domain( root_dn );
1145
1146                 /* cleanup */
1147                 ads_msgfree( ads, msg );
1148
1149                 /* try again for NS servers */
1150
1151                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1152
1153                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1154                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1155                          "realm\n", ads->config.realm));
1156                         goto done;
1157                 }
1158
1159                 dnsdomain = root_domain;
1160
1161         }
1162
1163         /* Now perform the dns update - we'll try non-secure and if we fail,
1164            we'll follow it up with a secure update */
1165
1166         fstrcpy( dns_server, nameservers[0].hostname );
1167
1168         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1169         if (!ERR_DNS_IS_OK(dns_err)) {
1170                 status = NT_STATUS_UNSUCCESSFUL;
1171         }
1172
1173 done:
1174
1175         SAFE_FREE( root_domain );
1176
1177         return status;
1178 }
1179
1180 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1181 {
1182         int num_addrs;
1183         struct sockaddr_storage *iplist = NULL;
1184         fstring machine_name;
1185         NTSTATUS status;
1186
1187         name_to_fqdn( machine_name, global_myname() );
1188         strlower_m( machine_name );
1189
1190         /* Get our ip address (not the 127.0.0.x address but a real ip
1191          * address) */
1192
1193         num_addrs = get_my_ip_address( &iplist );
1194         if ( num_addrs <= 0 ) {
1195                 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1196                          "addresses!\n"));
1197                 return NT_STATUS_INVALID_PARAMETER;
1198         }
1199
1200         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1201                                          iplist, num_addrs);
1202         SAFE_FREE( iplist );
1203         return status;
1204 }
1205 #endif
1206
1207
1208 /*******************************************************************
1209  ********************************************************************/
1210
1211 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1212 {
1213         d_printf(_("net ads join [options]\n"
1214                    "Valid options:\n"));
1215         d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
1216                    "                      The deault UPN is in the form host/netbiosname@REALM.\n"));
1217         d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
1218                    "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1219                    "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1220                    "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
1221                    "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
1222         d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
1223         d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
1224                    "                      NB: osName and osVer must be specified together for either to take effect.\n"
1225                    "                          Also, the operatingSystemService attribute is also set when along with\n"
1226                    "                          the two other attributes.\n"));
1227
1228         return -1;
1229 }
1230
1231 /*******************************************************************
1232  ********************************************************************/
1233
1234 int net_ads_join(struct net_context *c, int argc, const char **argv)
1235 {
1236         TALLOC_CTX *ctx = NULL;
1237         struct libnet_JoinCtx *r = NULL;
1238         const char *domain = lp_realm();
1239         WERROR werr = WERR_SETUP_NOT_JOINED;
1240         bool createupn = false;
1241         const char *machineupn = NULL;
1242         const char *create_in_ou = NULL;
1243         int i;
1244         const char *os_name = NULL;
1245         const char *os_version = NULL;
1246         bool modify_config = lp_config_backend_is_registry();
1247
1248         if (c->display_usage)
1249                 return net_ads_join_usage(c, argc, argv);
1250
1251         if (!modify_config) {
1252
1253                 werr = check_ads_config();
1254                 if (!W_ERROR_IS_OK(werr)) {
1255                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1256                         goto fail;
1257                 }
1258         }
1259
1260         if (!(ctx = talloc_init("net_ads_join"))) {
1261                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1262                 werr = WERR_NOMEM;
1263                 goto fail;
1264         }
1265
1266         if (!c->opt_kerberos) {
1267                 use_in_memory_ccache();
1268         }
1269
1270         werr = libnet_init_JoinCtx(ctx, &r);
1271         if (!W_ERROR_IS_OK(werr)) {
1272                 goto fail;
1273         }
1274
1275         /* process additional command line args */
1276
1277         for ( i=0; i<argc; i++ ) {
1278                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1279                         createupn = true;
1280                         machineupn = get_string_param(argv[i]);
1281                 }
1282                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1283                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1284                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1285                                 werr = WERR_INVALID_PARAM;
1286                                 goto fail;
1287                         }
1288                 }
1289                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1290                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1291                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1292                                 werr = WERR_INVALID_PARAM;
1293                                 goto fail;
1294                         }
1295                 }
1296                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1297                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1298                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1299                                 werr = WERR_INVALID_PARAM;
1300                                 goto fail;
1301                         }
1302                 }
1303                 else {
1304                         domain = argv[i];
1305                 }
1306         }
1307
1308         if (!*domain) {
1309                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1310                 werr = WERR_INVALID_PARAM;
1311                 goto fail;
1312         }
1313
1314         /* Do the domain join here */
1315
1316         r->in.domain_name       = domain;
1317         r->in.create_upn        = createupn;
1318         r->in.upn               = machineupn;
1319         r->in.account_ou        = create_in_ou;
1320         r->in.os_name           = os_name;
1321         r->in.os_version        = os_version;
1322         r->in.dc_name           = c->opt_host;
1323         r->in.admin_account     = c->opt_user_name;
1324         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1325         r->in.debug             = true;
1326         r->in.use_kerberos      = c->opt_kerberos;
1327         r->in.modify_config     = modify_config;
1328         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1329                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1330                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1331
1332         werr = libnet_Join(ctx, r);
1333         if (!W_ERROR_IS_OK(werr)) {
1334                 goto fail;
1335         }
1336
1337         /* Check the short name of the domain */
1338
1339         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1340                 d_printf(_("The workgroup in %s does not match the short\n"
1341                            "domain name obtained from the server.\n"
1342                            "Using the name [%s] from the server.\n"
1343                            "You should set \"workgroup = %s\" in %s.\n"),
1344                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1345                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1346         }
1347
1348         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1349
1350         if (r->out.dns_domain_name) {
1351                 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1352                         r->out.dns_domain_name);
1353         } else {
1354                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1355                         r->out.netbios_domain_name);
1356         }
1357
1358 #if defined(WITH_DNS_UPDATES)
1359         if (r->out.domain_is_ad) {
1360                 /* We enter this block with user creds */
1361                 ADS_STRUCT *ads_dns = NULL;
1362
1363                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1364                         /* kinit with the machine password */
1365
1366                         use_in_memory_ccache();
1367                         if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1368                                 goto fail;
1369                         }
1370                         ads_dns->auth.password = secrets_fetch_machine_password(
1371                                 r->out.netbios_domain_name, NULL, NULL );
1372                         ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1373                         strupper_m(ads_dns->auth.realm );
1374                         ads_kinit_password( ads_dns );
1375                 }
1376
1377                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1378                         d_fprintf( stderr, _("DNS update failed!\n") );
1379                 }
1380
1381                 /* exit from this block using machine creds */
1382                 ads_destroy(&ads_dns);
1383         }
1384 #endif
1385         TALLOC_FREE(r);
1386         TALLOC_FREE( ctx );
1387
1388         return 0;
1389
1390 fail:
1391         /* issue an overall failure message at the end. */
1392         d_printf(_("Failed to join domain: %s\n"),
1393                 r && r->out.error_string ? r->out.error_string :
1394                 get_friendly_werror_msg(werr));
1395         TALLOC_FREE( ctx );
1396
1397         return -1;
1398 }
1399
1400 /*******************************************************************
1401  ********************************************************************/
1402
1403 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1404 {
1405 #if defined(WITH_DNS_UPDATES)
1406         ADS_STRUCT *ads;
1407         ADS_STATUS status;
1408         TALLOC_CTX *ctx;
1409
1410 #ifdef DEVELOPER
1411         talloc_enable_leak_report();
1412 #endif
1413
1414         if (argc > 0 || c->display_usage) {
1415                 d_printf(_("Usage:\n"
1416                            "net ads dns register\n"
1417                            "    Register hostname with DNS\n"));
1418                 return -1;
1419         }
1420
1421         if (!(ctx = talloc_init("net_ads_dns"))) {
1422                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1423                 return -1;
1424         }
1425
1426         status = ads_startup(c, true, &ads);
1427         if ( !ADS_ERR_OK(status) ) {
1428                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1429                 TALLOC_FREE(ctx);
1430                 return -1;
1431         }
1432
1433         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1434                 d_fprintf( stderr, _("DNS update failed!\n") );
1435                 ads_destroy( &ads );
1436                 TALLOC_FREE( ctx );
1437                 return -1;
1438         }
1439
1440         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1441
1442         ads_destroy(&ads);
1443         TALLOC_FREE( ctx );
1444
1445         return 0;
1446 #else
1447         d_fprintf(stderr,
1448                   _("DNS update support not enabled at compile time!\n"));
1449         return -1;
1450 #endif
1451 }
1452
1453 #if defined(WITH_DNS_UPDATES)
1454 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1455 #endif
1456
1457 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1458 {
1459 #if defined(WITH_DNS_UPDATES)
1460         DNS_ERROR err;
1461
1462 #ifdef DEVELOPER
1463         talloc_enable_leak_report();
1464 #endif
1465
1466         if (argc != 2 || c->display_usage) {
1467                 d_printf(_("Usage:\n"
1468                            "net ads dns gethostbyname <server> <name>\n"
1469                            "  Look up hostname from the AD\n"
1470                            "    server\tName server to use\n"
1471                            "    name\tName to look up\n"));
1472                 return -1;
1473         }
1474
1475         err = do_gethostbyname(argv[0], argv[1]);
1476
1477         d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1478 #endif
1479         return 0;
1480 }
1481
1482 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1483 {
1484         struct functable func[] = {
1485                 {
1486                         "register",
1487                         net_ads_dns_register,
1488                         NET_TRANSPORT_ADS,
1489                         N_("Add host dns entry to AD"),
1490                         N_("net ads dns register\n"
1491                            "    Add host dns entry to AD")
1492                 },
1493                 {
1494                         "gethostbyname",
1495                         net_ads_dns_gethostbyname,
1496                         NET_TRANSPORT_ADS,
1497                         N_("Look up host"),
1498                         N_("net ads dns gethostbyname\n"
1499                            "    Look up host")
1500                 },
1501                 {NULL, NULL, 0, NULL, NULL}
1502         };
1503
1504         return net_run_function(c, argc, argv, "net ads dns", func);
1505 }
1506
1507 /*******************************************************************
1508  ********************************************************************/
1509
1510 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1511 {
1512         d_printf(_(
1513 "\nnet ads printer search <printer>"
1514 "\n\tsearch for a printer in the directory\n"
1515 "\nnet ads printer info <printer> <server>"
1516 "\n\tlookup info in directory for printer on server"
1517 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1518 "\nnet ads printer publish <printername>"
1519 "\n\tpublish printer in directory"
1520 "\n\t(note: printer name is required)\n"
1521 "\nnet ads printer remove <printername>"
1522 "\n\tremove printer from directory"
1523 "\n\t(note: printer name is required)\n"));
1524         return -1;
1525 }
1526
1527 /*******************************************************************
1528  ********************************************************************/
1529
1530 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1531 {
1532         ADS_STRUCT *ads;
1533         ADS_STATUS rc;
1534         LDAPMessage *res = NULL;
1535
1536         if (c->display_usage) {
1537                 d_printf(_("Usage:\n"
1538                            "net ads printer search\n"
1539                            "    List printers in the AD\n"));
1540                 return 0;
1541         }
1542
1543         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1544                 return -1;
1545         }
1546
1547         rc = ads_find_printers(ads, &res);
1548
1549         if (!ADS_ERR_OK(rc)) {
1550                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1551                 ads_msgfree(ads, res);
1552                 ads_destroy(&ads);
1553                 return -1;
1554         }
1555
1556         if (ads_count_replies(ads, res) == 0) {
1557                 d_fprintf(stderr, _("No results found\n"));
1558                 ads_msgfree(ads, res);
1559                 ads_destroy(&ads);
1560                 return -1;
1561         }
1562
1563         ads_dump(ads, res);
1564         ads_msgfree(ads, res);
1565         ads_destroy(&ads);
1566         return 0;
1567 }
1568
1569 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1570 {
1571         ADS_STRUCT *ads;
1572         ADS_STATUS rc;
1573         const char *servername, *printername;
1574         LDAPMessage *res = NULL;
1575
1576         if (c->display_usage) {
1577                 d_printf(_("Usage:\n"
1578                            "net ads printer info [printername [servername]]\n"
1579                            "  Display printer info from AD\n"
1580                            "    printername\tPrinter name or wildcard\n"
1581                            "    servername\tName of the print server\n"));
1582                 return 0;
1583         }
1584
1585         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1586                 return -1;
1587         }
1588
1589         if (argc > 0) {
1590                 printername = argv[0];
1591         } else {
1592                 printername = "*";
1593         }
1594
1595         if (argc > 1) {
1596                 servername =  argv[1];
1597         } else {
1598                 servername = global_myname();
1599         }
1600
1601         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1602
1603         if (!ADS_ERR_OK(rc)) {
1604                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1605                         servername, ads_errstr(rc));
1606                 ads_msgfree(ads, res);
1607                 ads_destroy(&ads);
1608                 return -1;
1609         }
1610
1611         if (ads_count_replies(ads, res) == 0) {
1612                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1613                 ads_msgfree(ads, res);
1614                 ads_destroy(&ads);
1615                 return -1;
1616         }
1617
1618         ads_dump(ads, res);
1619         ads_msgfree(ads, res);
1620         ads_destroy(&ads);
1621
1622         return 0;
1623 }
1624
1625 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1626 {
1627         ADS_STRUCT *ads;
1628         ADS_STATUS rc;
1629         const char *servername, *printername;
1630         struct cli_state *cli = NULL;
1631         struct rpc_pipe_client *pipe_hnd = NULL;
1632         struct sockaddr_storage server_ss;
1633         NTSTATUS nt_status;
1634         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1635         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1636         char *prt_dn, *srv_dn, **srv_cn;
1637         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1638         LDAPMessage *res = NULL;
1639
1640         if (argc < 1 || c->display_usage) {
1641                 d_printf(_("Usage:\n"
1642                            "net ads printer publish <printername> [servername]\n"
1643                            "  Publish printer in AD\n"
1644                            "    printername\tName of the printer\n"
1645                            "    servername\tName of the print server\n"));
1646                 talloc_destroy(mem_ctx);
1647                 return -1;
1648         }
1649
1650         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1651                 talloc_destroy(mem_ctx);
1652                 return -1;
1653         }
1654
1655         printername = argv[0];
1656
1657         if (argc == 2) {
1658                 servername = argv[1];
1659         } else {
1660                 servername = global_myname();
1661         }
1662
1663         /* Get printer data from SPOOLSS */
1664
1665         resolve_name(servername, &server_ss, 0x20, false);
1666
1667         nt_status = cli_full_connection(&cli, global_myname(), servername,
1668                                         &server_ss, 0,
1669                                         "IPC$", "IPC",
1670                                         c->opt_user_name, c->opt_workgroup,
1671                                         c->opt_password ? c->opt_password : "",
1672                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1673                                         Undefined, NULL);
1674
1675         if (NT_STATUS_IS_ERR(nt_status)) {
1676                 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1677                                     "obtain data for %s\n"),
1678                           servername, printername);
1679                 ads_destroy(&ads);
1680                 talloc_destroy(mem_ctx);
1681                 return -1;
1682         }
1683
1684         /* Publish on AD server */
1685
1686         ads_find_machine_acct(ads, &res, servername);
1687
1688         if (ads_count_replies(ads, res) == 0) {
1689                 d_fprintf(stderr, _("Could not find machine account for server "
1690                                     "%s\n"),
1691                          servername);
1692                 ads_destroy(&ads);
1693                 talloc_destroy(mem_ctx);
1694                 return -1;
1695         }
1696
1697         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1698         srv_cn = ldap_explode_dn(srv_dn, 1);
1699
1700         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1701         printername_escaped = escape_rdn_val_string_alloc(printername);
1702         if (!srv_cn_escaped || !printername_escaped) {
1703                 SAFE_FREE(srv_cn_escaped);
1704                 SAFE_FREE(printername_escaped);
1705                 d_fprintf(stderr, _("Internal error, out of memory!"));
1706                 ads_destroy(&ads);
1707                 talloc_destroy(mem_ctx);
1708                 return -1;
1709         }
1710
1711         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1712                 SAFE_FREE(srv_cn_escaped);
1713                 SAFE_FREE(printername_escaped);
1714                 d_fprintf(stderr, _("Internal error, out of memory!"));
1715                 ads_destroy(&ads);
1716                 talloc_destroy(mem_ctx);
1717                 return -1;
1718         }
1719
1720         SAFE_FREE(srv_cn_escaped);
1721         SAFE_FREE(printername_escaped);
1722
1723         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1724         if (!NT_STATUS_IS_OK(nt_status)) {
1725                 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1726                          servername);
1727                 SAFE_FREE(prt_dn);
1728                 ads_destroy(&ads);
1729                 talloc_destroy(mem_ctx);
1730                 return -1;
1731         }
1732
1733         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1734                                                               printername))) {
1735                 SAFE_FREE(prt_dn);
1736                 ads_destroy(&ads);
1737                 talloc_destroy(mem_ctx);
1738                 return -1;
1739         }
1740
1741         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1742         if (!ADS_ERR_OK(rc)) {
1743                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1744                 SAFE_FREE(prt_dn);
1745                 ads_destroy(&ads);
1746                 talloc_destroy(mem_ctx);
1747                 return -1;
1748         }
1749
1750         d_printf("published printer\n");
1751         SAFE_FREE(prt_dn);
1752         ads_destroy(&ads);
1753         talloc_destroy(mem_ctx);
1754
1755         return 0;
1756 }
1757
1758 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1759 {
1760         ADS_STRUCT *ads;
1761         ADS_STATUS rc;
1762         const char *servername;
1763         char *prt_dn;
1764         LDAPMessage *res = NULL;
1765
1766         if (argc < 1 || c->display_usage) {
1767                 d_printf(_("Usage:\n"
1768                            "net ads printer remove <printername> [servername]\n"
1769                            "  Remove a printer from the AD\n"
1770                            "    printername\tName of the printer\n"
1771                            "    servername\tName of the print server\n"));
1772                 return -1;
1773         }
1774
1775         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1776                 return -1;
1777         }
1778
1779         if (argc > 1) {
1780                 servername = argv[1];
1781         } else {
1782                 servername = global_myname();
1783         }
1784
1785         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1786
1787         if (!ADS_ERR_OK(rc)) {
1788                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1789                 ads_msgfree(ads, res);
1790                 ads_destroy(&ads);
1791                 return -1;
1792         }
1793
1794         if (ads_count_replies(ads, res) == 0) {
1795                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1796                 ads_msgfree(ads, res);
1797                 ads_destroy(&ads);
1798                 return -1;
1799         }
1800
1801         prt_dn = ads_get_dn(ads, talloc_tos(), res);
1802         ads_msgfree(ads, res);
1803         rc = ads_del_dn(ads, prt_dn);
1804         TALLOC_FREE(prt_dn);
1805
1806         if (!ADS_ERR_OK(rc)) {
1807                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1808                 ads_destroy(&ads);
1809                 return -1;
1810         }
1811
1812         ads_destroy(&ads);
1813         return 0;
1814 }
1815
1816 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1817 {
1818         struct functable func[] = {
1819                 {
1820                         "search",
1821                         net_ads_printer_search,
1822                         NET_TRANSPORT_ADS,
1823                         N_("Search for a printer"),
1824                         N_("net ads printer search\n"
1825                            "    Search for a printer")
1826                 },
1827                 {
1828                         "info",
1829                         net_ads_printer_info,
1830                         NET_TRANSPORT_ADS,
1831                         N_("Display printer information"),
1832                         N_("net ads printer info\n"
1833                            "    Display printer information")
1834                 },
1835                 {
1836                         "publish",
1837                         net_ads_printer_publish,
1838                         NET_TRANSPORT_ADS,
1839                         N_("Publish a printer"),
1840                         N_("net ads printer publish\n"
1841                            "    Publish a printer")
1842                 },
1843                 {
1844                         "remove",
1845                         net_ads_printer_remove,
1846                         NET_TRANSPORT_ADS,
1847                         N_("Delete a printer"),
1848                         N_("net ads printer remove\n"
1849                            "    Delete a printer")
1850                 },
1851                 {NULL, NULL, 0, NULL, NULL}
1852         };
1853
1854         return net_run_function(c, argc, argv, "net ads printer", func);
1855 }
1856
1857
1858 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1859 {
1860         ADS_STRUCT *ads;
1861         const char *auth_principal = c->opt_user_name;
1862         const char *auth_password = c->opt_password;
1863         char *realm = NULL;
1864         char *new_password = NULL;
1865         char *chr, *prompt;
1866         const char *user;
1867         ADS_STATUS ret;
1868
1869         if (c->display_usage) {
1870                 d_printf(_("Usage:\n"
1871                            "net ads password <username>\n"
1872                            "  Change password for user\n"
1873                            "    username\tName of user to change password for\n"));
1874                 return 0;
1875         }
1876
1877         if (c->opt_user_name == NULL || c->opt_password == NULL) {
1878                 d_fprintf(stderr, _("You must supply an administrator "
1879                                     "username/password\n"));
1880                 return -1;
1881         }
1882
1883         if (argc < 1) {
1884                 d_fprintf(stderr, _("ERROR: You must say which username to "
1885                                     "change password for\n"));
1886                 return -1;
1887         }
1888
1889         user = argv[0];
1890         if (!strchr_m(user, '@')) {
1891                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1892                         return -1;
1893                 }
1894                 user = chr;
1895         }
1896
1897         use_in_memory_ccache();
1898         chr = strchr_m(auth_principal, '@');
1899         if (chr) {
1900                 realm = ++chr;
1901         } else {
1902                 realm = lp_realm();
1903         }
1904
1905         /* use the realm so we can eventually change passwords for users
1906         in realms other than default */
1907         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1908                 return -1;
1909         }
1910
1911         /* we don't actually need a full connect, but it's the easy way to
1912                 fill in the KDC's addresss */
1913         ads_connect(ads);
1914
1915         if (!ads->config.realm) {
1916                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1917                 ads_destroy(&ads);
1918                 return -1;
1919         }
1920
1921         if (argv[1]) {
1922                 new_password = (char *)argv[1];
1923         } else {
1924                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1925                         return -1;
1926                 }
1927                 new_password = getpass(prompt);
1928                 free(prompt);
1929         }
1930
1931         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1932                                 auth_password, user, new_password, ads->auth.time_offset);
1933         if (!ADS_ERR_OK(ret)) {
1934                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1935                 ads_destroy(&ads);
1936                 return -1;
1937         }
1938
1939         d_printf(_("Password change for %s completed.\n"), user);
1940         ads_destroy(&ads);
1941
1942         return 0;
1943 }
1944
1945 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1946 {
1947         ADS_STRUCT *ads;
1948         char *host_principal;
1949         fstring my_name;
1950         ADS_STATUS ret;
1951
1952         if (c->display_usage) {
1953                 d_printf(_("Usage:\n"
1954                            "net ads changetrustpw\n"
1955                            "    Change the machine account's trust password\n"));
1956                 return 0;
1957         }
1958
1959         if (!secrets_init()) {
1960                 DEBUG(1,("Failed to initialise secrets database\n"));
1961                 return -1;
1962         }
1963
1964         net_use_krb_machine_account(c);
1965
1966         use_in_memory_ccache();
1967
1968         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1969                 return -1;
1970         }
1971
1972         fstrcpy(my_name, global_myname());
1973         strlower_m(my_name);
1974         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1975                 ads_destroy(&ads);
1976                 return -1;
1977         }
1978         d_printf(_("Changing password for principal: %s\n"), host_principal);
1979
1980         ret = ads_change_trust_account_password(ads, host_principal);
1981
1982         if (!ADS_ERR_OK(ret)) {
1983                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1984                 ads_destroy(&ads);
1985                 SAFE_FREE(host_principal);
1986                 return -1;
1987         }
1988
1989         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
1990
1991         if (USE_SYSTEM_KEYTAB) {
1992                 d_printf(_("Attempting to update system keytab with new password.\n"));
1993                 if (ads_keytab_create_default(ads)) {
1994                         d_printf(_("Failed to update system keytab.\n"));
1995                 }
1996         }
1997
1998         ads_destroy(&ads);
1999         SAFE_FREE(host_principal);
2000
2001         return 0;
2002 }
2003
2004 /*
2005   help for net ads search
2006 */
2007 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2008 {
2009         d_printf(_(
2010                 "\nnet ads search <expression> <attributes...>\n"
2011                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2012                 "The expression is a standard LDAP search expression, and the\n"
2013                 "attributes are a list of LDAP fields to show in the results.\n\n"
2014                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2015                 ));
2016         net_common_flags_usage(c, argc, argv);
2017         return -1;
2018 }
2019
2020
2021 /*
2022   general ADS search function. Useful in diagnosing problems in ADS
2023 */
2024 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2025 {
2026         ADS_STRUCT *ads;
2027         ADS_STATUS rc;
2028         const char *ldap_exp;
2029         const char **attrs;
2030         LDAPMessage *res = NULL;
2031
2032         if (argc < 1 || c->display_usage) {
2033                 return net_ads_search_usage(c, argc, argv);
2034         }
2035
2036         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2037                 return -1;
2038         }
2039
2040         ldap_exp = argv[0];
2041         attrs = (argv + 1);
2042
2043         rc = ads_do_search_all(ads, ads->config.bind_path,
2044                                LDAP_SCOPE_SUBTREE,
2045                                ldap_exp, attrs, &res);
2046         if (!ADS_ERR_OK(rc)) {
2047                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2048                 ads_destroy(&ads);
2049                 return -1;
2050         }
2051
2052         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2053
2054         /* dump the results */
2055         ads_dump(ads, res);
2056
2057         ads_msgfree(ads, res);
2058         ads_destroy(&ads);
2059
2060         return 0;
2061 }
2062
2063
2064 /*
2065   help for net ads search
2066 */
2067 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2068 {
2069         d_printf(_(
2070                 "\nnet ads dn <dn> <attributes...>\n"
2071                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2072                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2073                 "to show in the results\n\n"
2074                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2075                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2076                 ));
2077         net_common_flags_usage(c, argc, argv);
2078         return -1;
2079 }
2080
2081
2082 /*
2083   general ADS search function. Useful in diagnosing problems in ADS
2084 */
2085 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2086 {
2087         ADS_STRUCT *ads;
2088         ADS_STATUS rc;
2089         const char *dn;
2090         const char **attrs;
2091         LDAPMessage *res = NULL;
2092
2093         if (argc < 1 || c->display_usage) {
2094                 return net_ads_dn_usage(c, argc, argv);
2095         }
2096
2097         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2098                 return -1;
2099         }
2100
2101         dn = argv[0];
2102         attrs = (argv + 1);
2103
2104         rc = ads_do_search_all(ads, dn,
2105                                LDAP_SCOPE_BASE,
2106                                "(objectclass=*)", attrs, &res);
2107         if (!ADS_ERR_OK(rc)) {
2108                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2109                 ads_destroy(&ads);
2110                 return -1;
2111         }
2112
2113         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2114
2115         /* dump the results */
2116         ads_dump(ads, res);
2117
2118         ads_msgfree(ads, res);
2119         ads_destroy(&ads);
2120
2121         return 0;
2122 }
2123
2124 /*
2125   help for net ads sid search
2126 */
2127 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2128 {
2129         d_printf(_(
2130                 "\nnet ads sid <sid> <attributes...>\n"
2131                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2132                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2133                 "to show in the results\n\n"
2134                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2135                 ));
2136         net_common_flags_usage(c, argc, argv);
2137         return -1;
2138 }
2139
2140
2141 /*
2142   general ADS search function. Useful in diagnosing problems in ADS
2143 */
2144 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2145 {
2146         ADS_STRUCT *ads;
2147         ADS_STATUS rc;
2148         const char *sid_string;
2149         const char **attrs;
2150         LDAPMessage *res = NULL;
2151         DOM_SID sid;
2152
2153         if (argc < 1 || c->display_usage) {
2154                 return net_ads_sid_usage(c, argc, argv);
2155         }
2156
2157         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2158                 return -1;
2159         }
2160
2161         sid_string = argv[0];
2162         attrs = (argv + 1);
2163
2164         if (!string_to_sid(&sid, sid_string)) {
2165                 d_fprintf(stderr, _("could not convert sid\n"));
2166                 ads_destroy(&ads);
2167                 return -1;
2168         }
2169
2170         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2171         if (!ADS_ERR_OK(rc)) {
2172                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2173                 ads_destroy(&ads);
2174                 return -1;
2175         }
2176
2177         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2178
2179         /* dump the results */
2180         ads_dump(ads, res);
2181
2182         ads_msgfree(ads, res);
2183         ads_destroy(&ads);
2184
2185         return 0;
2186 }
2187
2188 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2189 {
2190         int ret;
2191         ADS_STRUCT *ads;
2192
2193         if (c->display_usage) {
2194                 d_printf(_("Usage:\n"
2195                            "net ads keytab flush\n"
2196                            "    Delete the whole keytab\n"));
2197                 return 0;
2198         }
2199
2200         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2201                 return -1;
2202         }
2203         ret = ads_keytab_flush(ads);
2204         ads_destroy(&ads);
2205         return ret;
2206 }
2207
2208 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2209 {
2210         int i;
2211         int ret = 0;
2212         ADS_STRUCT *ads;
2213
2214         if (c->display_usage) {
2215                 d_printf(_("Usage:\n"
2216                            "net ads keytab add <principal> [principal ...]\n"
2217                            "  Add principals to local keytab\n"
2218                            "    principal\tKerberos principal to add to "
2219                            "keytab\n"));
2220                 return 0;
2221         }
2222
2223         d_printf(_("Processing principals to add...\n"));
2224         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2225                 return -1;
2226         }
2227         for (i = 0; i < argc; i++) {
2228                 ret |= ads_keytab_add_entry(ads, argv[i]);
2229         }
2230         ads_destroy(&ads);
2231         return ret;
2232 }
2233
2234 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2235 {
2236         ADS_STRUCT *ads;
2237         int ret;
2238
2239         if (c->display_usage) {
2240                 d_printf(_("Usage:\n"
2241                            "net ads keytab create\n"
2242                            "    Create new default keytab\n"));
2243                 return 0;
2244         }
2245
2246         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2247                 return -1;
2248         }
2249         ret = ads_keytab_create_default(ads);
2250         ads_destroy(&ads);
2251         return ret;
2252 }
2253
2254 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2255 {
2256         const char *keytab = NULL;
2257
2258         if (c->display_usage) {
2259                 d_printf(_("Usage:\n"
2260                            "net ads keytab list [keytab]\n"
2261                            "  List a local keytab\n"
2262                            "    keytab\tKeytab to list\n"));
2263                 return 0;
2264         }
2265
2266         if (argc >= 1) {
2267                 keytab = argv[0];
2268         }
2269
2270         return ads_keytab_list(keytab);
2271 }
2272
2273
2274 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2275 {
2276         struct functable func[] = {
2277                 {
2278                         "add",
2279                         net_ads_keytab_add,
2280                         NET_TRANSPORT_ADS,
2281                         N_("Add a service principal"),
2282                         N_("net ads keytab add\n"
2283                            "    Add a service principal")
2284                 },
2285                 {
2286                         "create",
2287                         net_ads_keytab_create,
2288                         NET_TRANSPORT_ADS,
2289                         N_("Create a fresh keytab"),
2290                         N_("net ads keytab create\n"
2291                            "    Create a fresh keytab")
2292                 },
2293                 {
2294                         "flush",
2295                         net_ads_keytab_flush,
2296                         NET_TRANSPORT_ADS,
2297                         N_("Remove all keytab entries"),
2298                         N_("net ads keytab flush\n"
2299                            "    Remove all keytab entries")
2300                 },
2301                 {
2302                         "list",
2303                         net_ads_keytab_list,
2304                         NET_TRANSPORT_ADS,
2305                         N_("List a keytab"),
2306                         N_("net ads keytab list\n"
2307                            "    List a keytab")
2308                 },
2309                 {NULL, NULL, 0, NULL, NULL}
2310         };
2311
2312         if (!USE_KERBEROS_KEYTAB) {
2313                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2314                     "keytab method to use keytab functions.\n"));
2315         }
2316
2317         return net_run_function(c, argc, argv, "net ads keytab", func);
2318 }
2319
2320 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2321 {
2322         int ret = -1;
2323
2324         if (c->display_usage) {
2325                 d_printf(_("Usage:\n"
2326                            "net ads kerberos renew\n"
2327                            "    Renew TGT from existing credential cache\n"));
2328                 return 0;
2329         }
2330
2331         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2332         if (ret) {
2333                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2334                         error_message(ret));
2335         }
2336         return ret;
2337 }
2338
2339 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2340 {
2341         struct PAC_DATA *pac = NULL;
2342         struct PAC_LOGON_INFO *info = NULL;
2343         TALLOC_CTX *mem_ctx = NULL;
2344         NTSTATUS status;
2345         int ret = -1;
2346         const char *impersonate_princ_s = NULL;
2347
2348         if (c->display_usage) {
2349                 d_printf(_("Usage:\n"
2350                            "net ads kerberos pac\n"
2351                            "    Dump the Kerberos PAC\n"));
2352                 return 0;
2353         }
2354
2355         mem_ctx = talloc_init("net_ads_kerberos_pac");
2356         if (!mem_ctx) {
2357                 goto out;
2358         }
2359
2360         if (argc > 0) {
2361                 impersonate_princ_s = argv[0];
2362         }
2363
2364         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2365
2366         status = kerberos_return_pac(mem_ctx,
2367                                      c->opt_user_name,
2368                                      c->opt_password,
2369                                      0,
2370                                      NULL,
2371                                      NULL,
2372                                      NULL,
2373                                      true,
2374                                      true,
2375                                      2592000, /* one month */
2376                                      impersonate_princ_s,
2377                                      &pac);
2378         if (!NT_STATUS_IS_OK(status)) {
2379                 d_printf(_("failed to query kerberos PAC: %s\n"),
2380                         nt_errstr(status));
2381                 goto out;
2382         }
2383
2384         info = get_logon_info_from_pac(pac);
2385         if (info) {
2386                 const char *s;
2387                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2388                 d_printf(_("The Pac: %s\n"), s);
2389         }
2390
2391         ret = 0;
2392  out:
2393         TALLOC_FREE(mem_ctx);
2394         return ret;
2395 }
2396
2397 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2398 {
2399         TALLOC_CTX *mem_ctx = NULL;
2400         int ret = -1;
2401         NTSTATUS status;
2402
2403         if (c->display_usage) {
2404                 d_printf(_("Usage:\n"
2405                            "net ads kerberos kinit\n"
2406                            "    Get Ticket Granting Ticket (TGT) for the user\n"));
2407                 return 0;
2408         }
2409
2410         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2411         if (!mem_ctx) {
2412                 goto out;
2413         }
2414
2415         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2416
2417         ret = kerberos_kinit_password_ext(c->opt_user_name,
2418                                           c->opt_password,
2419                                           0,
2420                                           NULL,
2421                                           NULL,
2422                                           NULL,
2423                                           true,
2424                                           true,
2425                                           2592000, /* one month */
2426                                           &status);
2427         if (ret) {
2428                 d_printf(_("failed to kinit password: %s\n"),
2429                         nt_errstr(status));
2430         }
2431  out:
2432         return ret;
2433 }
2434
2435 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2436 {
2437         struct functable func[] = {
2438                 {
2439                         "kinit",
2440                         net_ads_kerberos_kinit,
2441                         NET_TRANSPORT_ADS,
2442                         N_("Retrieve Ticket Granting Ticket (TGT)"),
2443                         N_("net ads kerberos kinit\n"
2444                            "    Receive Ticket Granting Ticket (TGT)")
2445                 },
2446                 {
2447                         "renew",
2448                         net_ads_kerberos_renew,
2449                         NET_TRANSPORT_ADS,
2450                         N_("Renew Ticket Granting Ticket from credential cache"),
2451                         N_("net ads kerberos renew\n"
2452                            "    Renew Ticket Granting Ticket (TGT) from "
2453                            "credential cache")
2454                 },
2455                 {
2456                         "pac",
2457                         net_ads_kerberos_pac,
2458                         NET_TRANSPORT_ADS,
2459                         N_("Dump Kerberos PAC"),
2460                         N_("net ads kerberos pac\n"
2461                            "    Dump Kerberos PAC")
2462                 },
2463                 {NULL, NULL, 0, NULL, NULL}
2464         };
2465
2466         return net_run_function(c, argc, argv, "net ads kerberos", func);
2467 }
2468
2469 int net_ads(struct net_context *c, int argc, const char **argv)
2470 {
2471         struct functable func[] = {
2472                 {
2473                         "info",
2474                         net_ads_info,
2475                         NET_TRANSPORT_ADS,
2476                         N_("Display details on remote ADS server"),
2477                         N_("net ads info\n"
2478                            "    Display details on remote ADS server")
2479                 },
2480                 {
2481                         "join",
2482                         net_ads_join,
2483                         NET_TRANSPORT_ADS,
2484                         N_("Join the local machine to ADS realm"),
2485                         N_("net ads join\n"
2486                            "    Join the local machine to ADS realm")
2487                 },
2488                 {
2489                         "testjoin",
2490                         net_ads_testjoin,
2491                         NET_TRANSPORT_ADS,
2492                         N_("Validate machine account"),
2493                         N_("net ads testjoin\n"
2494                            "    Validate machine account")
2495                 },
2496                 {
2497                         "leave",
2498                         net_ads_leave,
2499                         NET_TRANSPORT_ADS,
2500                         N_("Remove the local machine from ADS"),
2501                         N_("net ads leave\n"
2502                            "    Remove the local machine from ADS")
2503                 },
2504                 {
2505                         "status",
2506                         net_ads_status,
2507                         NET_TRANSPORT_ADS,
2508                         N_("Display machine account details"),
2509                         N_("net ads status\n"
2510                            "    Display machine account details")
2511                 },
2512                 {
2513                         "user",
2514                         net_ads_user,
2515                         NET_TRANSPORT_ADS,
2516                         N_("List/modify users"),
2517                         N_("net ads user\n"
2518                            "    List/modify users")
2519                 },
2520                 {
2521                         "group",
2522                         net_ads_group,
2523                         NET_TRANSPORT_ADS,
2524                         N_("List/modify groups"),
2525                         N_("net ads group\n"
2526                            "    List/modify groups")
2527                 },
2528                 {
2529                         "dns",
2530                         net_ads_dns,
2531                         NET_TRANSPORT_ADS,
2532                         N_("Issue dynamic DNS update"),
2533                         N_("net ads dns\n"
2534                            "    Issue dynamic DNS update")
2535                 },
2536                 {
2537                         "password",
2538                         net_ads_password,
2539                         NET_TRANSPORT_ADS,
2540                         N_("Change user passwords"),
2541                         N_("net ads password\n"
2542                            "    Change user passwords")
2543                 },
2544                 {
2545                         "changetrustpw",
2546                         net_ads_changetrustpw,
2547                         NET_TRANSPORT_ADS,
2548                         N_("Change trust account password"),
2549                         N_("net ads changetrustpw\n"
2550                            "    Change trust account password")
2551                 },
2552                 {
2553                         "printer",
2554                         net_ads_printer,
2555                         NET_TRANSPORT_ADS,
2556                         N_("List/modify printer entries"),
2557                         N_("net ads printer\n"
2558                            "    List/modify printer entries")
2559                 },
2560                 {
2561                         "search",
2562                         net_ads_search,
2563                         NET_TRANSPORT_ADS,
2564                         N_("Issue LDAP search using filter"),
2565                         N_("net ads search\n"
2566                            "    Issue LDAP search using filter")
2567                 },
2568                 {
2569                         "dn",
2570                         net_ads_dn,
2571                         NET_TRANSPORT_ADS,
2572                         N_("Issue LDAP search by DN"),
2573                         N_("net ads dn\n"
2574                            "    Issue LDAP search by DN")
2575                 },
2576                 {
2577                         "sid",
2578                         net_ads_sid,
2579                         NET_TRANSPORT_ADS,
2580                         N_("Issue LDAP search by SID"),
2581                         N_("net ads sid\n"
2582                            "    Issue LDAP search by SID")
2583                 },
2584                 {
2585                         "workgroup",
2586                         net_ads_workgroup,
2587                         NET_TRANSPORT_ADS,
2588                         N_("Display workgroup name"),
2589                         N_("net ads workgroup\n"
2590                            "    Display the workgroup name")
2591                 },
2592                 {
2593                         "lookup",
2594                         net_ads_lookup,
2595                         NET_TRANSPORT_ADS,
2596                         N_("Perfom CLDAP query on DC"),
2597                         N_("net ads lookup\n"
2598                            "    Find the ADS DC using CLDAP lookups")
2599                 },
2600                 {
2601                         "keytab",
2602                         net_ads_keytab,
2603                         NET_TRANSPORT_ADS,
2604                         N_("Manage local keytab file"),
2605                         N_("net ads keytab\n"
2606                            "    Manage local keytab file")
2607                 },
2608                 {
2609                         "gpo",
2610                         net_ads_gpo,
2611                         NET_TRANSPORT_ADS,
2612                         N_("Manage group policy objects"),
2613                         N_("net ads gpo\n"
2614                            "    Manage group policy objects")
2615                 },
2616                 {
2617                         "kerberos",
2618                         net_ads_kerberos,
2619                         NET_TRANSPORT_ADS,
2620                         N_("Manage kerberos keytab"),
2621                         N_("net ads kerberos\n"
2622                            "    Manage kerberos keytab")
2623                 },
2624                 {NULL, NULL, 0, NULL, NULL}
2625         };
2626
2627         return net_run_function(c, argc, argv, "net ads", func);
2628 }
2629
2630 #else
2631
2632 static int net_ads_noads(void)
2633 {
2634         d_fprintf(stderr, _("ADS support not compiled in\n"));
2635         return -1;
2636 }
2637
2638 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2639 {
2640         return net_ads_noads();
2641 }
2642
2643 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2644 {
2645         return net_ads_noads();
2646 }
2647
2648 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2649 {
2650         return net_ads_noads();
2651 }
2652
2653 int net_ads_join(struct net_context *c, int argc, const char **argv)
2654 {
2655         return net_ads_noads();
2656 }
2657
2658 int net_ads_user(struct net_context *c, int argc, const char **argv)
2659 {
2660         return net_ads_noads();
2661 }
2662
2663 int net_ads_group(struct net_context *c, int argc, const char **argv)
2664 {
2665         return net_ads_noads();
2666 }
2667
2668 /* this one shouldn't display a message */
2669 int net_ads_check(struct net_context *c)
2670 {
2671         return -1;
2672 }
2673
2674 int net_ads_check_our_domain(struct net_context *c)
2675 {
2676         return -1;
2677 }
2678
2679 int net_ads(struct net_context *c, int argc, const char **argv)
2680 {
2681         return net_ads_noads();
2682 }
2683
2684 #endif  /* WITH_ADS */