s3-net: use generated krb5.conf in 'net ads testjoin'
[kai/samba.git] / source3 / utils / net_ads.c
1 /*
2    Samba Unix/Linux SMB client library
3    net ads commands
4    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "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         fstring dc_name;
1011         struct sockaddr_storage dcip;
1012
1013         if (!secrets_init()) {
1014                 DEBUG(1,("Failed to initialise secrets database\n"));
1015                 return NT_STATUS_ACCESS_DENIED;
1016         }
1017
1018         net_use_krb_machine_account(c);
1019
1020         get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1021
1022         status = ads_startup(c, true, &ads);
1023         if (!ADS_ERR_OK(status)) {
1024                 return ads_ntstatus(status);
1025         }
1026
1027         ads_destroy(&ads);
1028         return NT_STATUS_OK;
1029 }
1030
1031 /*
1032   check that an existing join is OK
1033  */
1034 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1035 {
1036         NTSTATUS status;
1037         use_in_memory_ccache();
1038
1039         if (c->display_usage) {
1040                 d_printf(_("Usage:\n"
1041                            "net ads testjoin\n"
1042                            "    Test if the existing join is ok\n"));
1043                 return 0;
1044         }
1045
1046         /* Display success or failure */
1047         status = net_ads_join_ok(c);
1048         if (!NT_STATUS_IS_OK(status)) {
1049                 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1050                         get_friendly_nt_error_msg(status));
1051                 return -1;
1052         }
1053
1054         printf(_("Join is OK\n"));
1055         return 0;
1056 }
1057
1058 /*******************************************************************
1059   Simple configu checks before beginning the join
1060  ********************************************************************/
1061
1062 static WERROR check_ads_config( void )
1063 {
1064         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1065                 d_printf(_("Host is not configured as a member server.\n"));
1066                 return WERR_INVALID_DOMAIN_ROLE;
1067         }
1068
1069         if (strlen(global_myname()) > 15) {
1070                 d_printf(_("Our netbios name can be at most 15 chars long, "
1071                            "\"%s\" is %u chars long\n"), global_myname(),
1072                          (unsigned int)strlen(global_myname()));
1073                 return WERR_INVALID_COMPUTERNAME;
1074         }
1075
1076         if ( lp_security() == SEC_ADS && !*lp_realm()) {
1077                 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1078                           "join to succeed.\n"), get_dyn_CONFIGFILE());
1079                 return WERR_INVALID_PARAM;
1080         }
1081
1082         return WERR_OK;
1083 }
1084
1085 /*******************************************************************
1086  Send a DNS update request
1087 *******************************************************************/
1088
1089 #if defined(WITH_DNS_UPDATES)
1090 #include "dns.h"
1091 DNS_ERROR DoDNSUpdate(char *pszServerName,
1092                       const char *pszDomainName, const char *pszHostName,
1093                       const struct sockaddr_storage *sslist,
1094                       size_t num_addrs );
1095
1096 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1097                                         const char *machine_name,
1098                                         const struct sockaddr_storage *addrs,
1099                                         int num_addrs)
1100 {
1101         struct dns_rr_ns *nameservers = NULL;
1102         int ns_count = 0;
1103         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1104         DNS_ERROR dns_err;
1105         fstring dns_server;
1106         const char *dnsdomain = NULL;
1107         char *root_domain = NULL;
1108
1109         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1110                 d_printf(_("No DNS domain configured for %s. "
1111                            "Unable to perform DNS Update.\n"), machine_name);
1112                 status = NT_STATUS_INVALID_PARAMETER;
1113                 goto done;
1114         }
1115         dnsdomain++;
1116
1117         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1118         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1119                 /* Child domains often do not have NS records.  Look
1120                    for the NS record for the forest root domain
1121                    (rootDomainNamingContext in therootDSE) */
1122
1123                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
1124                 LDAPMessage *msg = NULL;
1125                 char *root_dn;
1126                 ADS_STATUS ads_status;
1127
1128                 if ( !ads->ldap.ld ) {
1129                         ads_status = ads_connect( ads );
1130                         if ( !ADS_ERR_OK(ads_status) ) {
1131                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1132                                 goto done;
1133                         }
1134                 }
1135
1136                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1137                                        "(objectclass=*)", rootname_attrs, &msg);
1138                 if (!ADS_ERR_OK(ads_status)) {
1139                         goto done;
1140                 }
1141
1142                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
1143                 if ( !root_dn ) {
1144                         ads_msgfree( ads, msg );
1145                         goto done;
1146                 }
1147
1148                 root_domain = ads_build_domain( root_dn );
1149
1150                 /* cleanup */
1151                 ads_msgfree( ads, msg );
1152
1153                 /* try again for NS servers */
1154
1155                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1156
1157                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1158                         DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1159                          "realm\n", ads->config.realm));
1160                         goto done;
1161                 }
1162
1163                 dnsdomain = root_domain;
1164
1165         }
1166
1167         /* Now perform the dns update - we'll try non-secure and if we fail,
1168            we'll follow it up with a secure update */
1169
1170         fstrcpy( dns_server, nameservers[0].hostname );
1171
1172         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1173         if (!ERR_DNS_IS_OK(dns_err)) {
1174                 status = NT_STATUS_UNSUCCESSFUL;
1175         }
1176
1177 done:
1178
1179         SAFE_FREE( root_domain );
1180
1181         return status;
1182 }
1183
1184 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1185 {
1186         int num_addrs;
1187         struct sockaddr_storage *iplist = NULL;
1188         fstring machine_name;
1189         NTSTATUS status;
1190
1191         name_to_fqdn( machine_name, global_myname() );
1192         strlower_m( machine_name );
1193
1194         /* Get our ip address (not the 127.0.0.x address but a real ip
1195          * address) */
1196
1197         num_addrs = get_my_ip_address( &iplist );
1198         if ( num_addrs <= 0 ) {
1199                 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1200                          "addresses!\n"));
1201                 return NT_STATUS_INVALID_PARAMETER;
1202         }
1203
1204         status = net_update_dns_internal(mem_ctx, ads, machine_name,
1205                                          iplist, num_addrs);
1206         SAFE_FREE( iplist );
1207         return status;
1208 }
1209 #endif
1210
1211
1212 /*******************************************************************
1213  ********************************************************************/
1214
1215 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1216 {
1217         d_printf(_("net ads join [options]\n"
1218                    "Valid options:\n"));
1219         d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
1220                    "                      The deault UPN is in the form host/netbiosname@REALM.\n"));
1221         d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
1222                    "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1223                    "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1224                    "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
1225                    "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
1226         d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
1227         d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
1228                    "                      NB: osName and osVer must be specified together for either to take effect.\n"
1229                    "                          Also, the operatingSystemService attribute is also set when along with\n"
1230                    "                          the two other attributes.\n"));
1231
1232         return -1;
1233 }
1234
1235 /*******************************************************************
1236  ********************************************************************/
1237
1238 int net_ads_join(struct net_context *c, int argc, const char **argv)
1239 {
1240         TALLOC_CTX *ctx = NULL;
1241         struct libnet_JoinCtx *r = NULL;
1242         const char *domain = lp_realm();
1243         WERROR werr = WERR_SETUP_NOT_JOINED;
1244         bool createupn = false;
1245         const char *machineupn = NULL;
1246         const char *create_in_ou = NULL;
1247         int i;
1248         const char *os_name = NULL;
1249         const char *os_version = NULL;
1250         bool modify_config = lp_config_backend_is_registry();
1251
1252         if (c->display_usage)
1253                 return net_ads_join_usage(c, argc, argv);
1254
1255         if (!modify_config) {
1256
1257                 werr = check_ads_config();
1258                 if (!W_ERROR_IS_OK(werr)) {
1259                         d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
1260                         goto fail;
1261                 }
1262         }
1263
1264         if (!(ctx = talloc_init("net_ads_join"))) {
1265                 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1266                 werr = WERR_NOMEM;
1267                 goto fail;
1268         }
1269
1270         if (!c->opt_kerberos) {
1271                 use_in_memory_ccache();
1272         }
1273
1274         werr = libnet_init_JoinCtx(ctx, &r);
1275         if (!W_ERROR_IS_OK(werr)) {
1276                 goto fail;
1277         }
1278
1279         /* process additional command line args */
1280
1281         for ( i=0; i<argc; i++ ) {
1282                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1283                         createupn = true;
1284                         machineupn = get_string_param(argv[i]);
1285                 }
1286                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1287                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1288                                 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1289                                 werr = WERR_INVALID_PARAM;
1290                                 goto fail;
1291                         }
1292                 }
1293                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1294                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
1295                                 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1296                                 werr = WERR_INVALID_PARAM;
1297                                 goto fail;
1298                         }
1299                 }
1300                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1301                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
1302                                 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1303                                 werr = WERR_INVALID_PARAM;
1304                                 goto fail;
1305                         }
1306                 }
1307                 else {
1308                         domain = argv[i];
1309                 }
1310         }
1311
1312         if (!*domain) {
1313                 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1314                 werr = WERR_INVALID_PARAM;
1315                 goto fail;
1316         }
1317
1318         /* Do the domain join here */
1319
1320         r->in.domain_name       = domain;
1321         r->in.create_upn        = createupn;
1322         r->in.upn               = machineupn;
1323         r->in.account_ou        = create_in_ou;
1324         r->in.os_name           = os_name;
1325         r->in.os_version        = os_version;
1326         r->in.dc_name           = c->opt_host;
1327         r->in.admin_account     = c->opt_user_name;
1328         r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
1329         r->in.debug             = true;
1330         r->in.use_kerberos      = c->opt_kerberos;
1331         r->in.modify_config     = modify_config;
1332         r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1333                                   WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1334                                   WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1335
1336         werr = libnet_Join(ctx, r);
1337         if (!W_ERROR_IS_OK(werr)) {
1338                 goto fail;
1339         }
1340
1341         /* Check the short name of the domain */
1342
1343         if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1344                 d_printf(_("The workgroup in %s does not match the short\n"
1345                            "domain name obtained from the server.\n"
1346                            "Using the name [%s] from the server.\n"
1347                            "You should set \"workgroup = %s\" in %s.\n"),
1348                          get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1349                          r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1350         }
1351
1352         d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1353
1354         if (r->out.dns_domain_name) {
1355                 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1356                         r->out.dns_domain_name);
1357         } else {
1358                 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1359                         r->out.netbios_domain_name);
1360         }
1361
1362 #if defined(WITH_DNS_UPDATES)
1363         if (r->out.domain_is_ad) {
1364                 /* We enter this block with user creds */
1365                 ADS_STRUCT *ads_dns = NULL;
1366
1367                 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1368                         /* kinit with the machine password */
1369
1370                         use_in_memory_ccache();
1371                         if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1372                                 goto fail;
1373                         }
1374                         ads_dns->auth.password = secrets_fetch_machine_password(
1375                                 r->out.netbios_domain_name, NULL, NULL );
1376                         ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1377                         strupper_m(ads_dns->auth.realm );
1378                         ads_kinit_password( ads_dns );
1379                 }
1380
1381                 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1382                         d_fprintf( stderr, _("DNS update failed!\n") );
1383                 }
1384
1385                 /* exit from this block using machine creds */
1386                 ads_destroy(&ads_dns);
1387         }
1388 #endif
1389         TALLOC_FREE(r);
1390         TALLOC_FREE( ctx );
1391
1392         return 0;
1393
1394 fail:
1395         /* issue an overall failure message at the end. */
1396         d_printf(_("Failed to join domain: %s\n"),
1397                 r && r->out.error_string ? r->out.error_string :
1398                 get_friendly_werror_msg(werr));
1399         TALLOC_FREE( ctx );
1400
1401         return -1;
1402 }
1403
1404 /*******************************************************************
1405  ********************************************************************/
1406
1407 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1408 {
1409 #if defined(WITH_DNS_UPDATES)
1410         ADS_STRUCT *ads;
1411         ADS_STATUS status;
1412         TALLOC_CTX *ctx;
1413
1414 #ifdef DEVELOPER
1415         talloc_enable_leak_report();
1416 #endif
1417
1418         if (argc > 0 || c->display_usage) {
1419                 d_printf(_("Usage:\n"
1420                            "net ads dns register\n"
1421                            "    Register hostname with DNS\n"));
1422                 return -1;
1423         }
1424
1425         if (!(ctx = talloc_init("net_ads_dns"))) {
1426                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1427                 return -1;
1428         }
1429
1430         status = ads_startup(c, true, &ads);
1431         if ( !ADS_ERR_OK(status) ) {
1432                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1433                 TALLOC_FREE(ctx);
1434                 return -1;
1435         }
1436
1437         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1438                 d_fprintf( stderr, _("DNS update failed!\n") );
1439                 ads_destroy( &ads );
1440                 TALLOC_FREE( ctx );
1441                 return -1;
1442         }
1443
1444         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1445
1446         ads_destroy(&ads);
1447         TALLOC_FREE( ctx );
1448
1449         return 0;
1450 #else
1451         d_fprintf(stderr,
1452                   _("DNS update support not enabled at compile time!\n"));
1453         return -1;
1454 #endif
1455 }
1456
1457 #if defined(WITH_DNS_UPDATES)
1458 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1459 #endif
1460
1461 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1462 {
1463 #if defined(WITH_DNS_UPDATES)
1464         DNS_ERROR err;
1465
1466 #ifdef DEVELOPER
1467         talloc_enable_leak_report();
1468 #endif
1469
1470         if (argc != 2 || c->display_usage) {
1471                 d_printf(_("Usage:\n"
1472                            "net ads dns gethostbyname <server> <name>\n"
1473                            "  Look up hostname from the AD\n"
1474                            "    server\tName server to use\n"
1475                            "    name\tName to look up\n"));
1476                 return -1;
1477         }
1478
1479         err = do_gethostbyname(argv[0], argv[1]);
1480
1481         d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1482 #endif
1483         return 0;
1484 }
1485
1486 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1487 {
1488         struct functable func[] = {
1489                 {
1490                         "register",
1491                         net_ads_dns_register,
1492                         NET_TRANSPORT_ADS,
1493                         N_("Add host dns entry to AD"),
1494                         N_("net ads dns register\n"
1495                            "    Add host dns entry to AD")
1496                 },
1497                 {
1498                         "gethostbyname",
1499                         net_ads_dns_gethostbyname,
1500                         NET_TRANSPORT_ADS,
1501                         N_("Look up host"),
1502                         N_("net ads dns gethostbyname\n"
1503                            "    Look up host")
1504                 },
1505                 {NULL, NULL, 0, NULL, NULL}
1506         };
1507
1508         return net_run_function(c, argc, argv, "net ads dns", func);
1509 }
1510
1511 /*******************************************************************
1512  ********************************************************************/
1513
1514 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1515 {
1516         d_printf(_(
1517 "\nnet ads printer search <printer>"
1518 "\n\tsearch for a printer in the directory\n"
1519 "\nnet ads printer info <printer> <server>"
1520 "\n\tlookup info in directory for printer on server"
1521 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1522 "\nnet ads printer publish <printername>"
1523 "\n\tpublish printer in directory"
1524 "\n\t(note: printer name is required)\n"
1525 "\nnet ads printer remove <printername>"
1526 "\n\tremove printer from directory"
1527 "\n\t(note: printer name is required)\n"));
1528         return -1;
1529 }
1530
1531 /*******************************************************************
1532  ********************************************************************/
1533
1534 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1535 {
1536         ADS_STRUCT *ads;
1537         ADS_STATUS rc;
1538         LDAPMessage *res = NULL;
1539
1540         if (c->display_usage) {
1541                 d_printf(_("Usage:\n"
1542                            "net ads printer search\n"
1543                            "    List printers in the AD\n"));
1544                 return 0;
1545         }
1546
1547         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1548                 return -1;
1549         }
1550
1551         rc = ads_find_printers(ads, &res);
1552
1553         if (!ADS_ERR_OK(rc)) {
1554                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1555                 ads_msgfree(ads, res);
1556                 ads_destroy(&ads);
1557                 return -1;
1558         }
1559
1560         if (ads_count_replies(ads, res) == 0) {
1561                 d_fprintf(stderr, _("No results found\n"));
1562                 ads_msgfree(ads, res);
1563                 ads_destroy(&ads);
1564                 return -1;
1565         }
1566
1567         ads_dump(ads, res);
1568         ads_msgfree(ads, res);
1569         ads_destroy(&ads);
1570         return 0;
1571 }
1572
1573 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1574 {
1575         ADS_STRUCT *ads;
1576         ADS_STATUS rc;
1577         const char *servername, *printername;
1578         LDAPMessage *res = NULL;
1579
1580         if (c->display_usage) {
1581                 d_printf(_("Usage:\n"
1582                            "net ads printer info [printername [servername]]\n"
1583                            "  Display printer info from AD\n"
1584                            "    printername\tPrinter name or wildcard\n"
1585                            "    servername\tName of the print server\n"));
1586                 return 0;
1587         }
1588
1589         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1590                 return -1;
1591         }
1592
1593         if (argc > 0) {
1594                 printername = argv[0];
1595         } else {
1596                 printername = "*";
1597         }
1598
1599         if (argc > 1) {
1600                 servername =  argv[1];
1601         } else {
1602                 servername = global_myname();
1603         }
1604
1605         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1606
1607         if (!ADS_ERR_OK(rc)) {
1608                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1609                         servername, ads_errstr(rc));
1610                 ads_msgfree(ads, res);
1611                 ads_destroy(&ads);
1612                 return -1;
1613         }
1614
1615         if (ads_count_replies(ads, res) == 0) {
1616                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1617                 ads_msgfree(ads, res);
1618                 ads_destroy(&ads);
1619                 return -1;
1620         }
1621
1622         ads_dump(ads, res);
1623         ads_msgfree(ads, res);
1624         ads_destroy(&ads);
1625
1626         return 0;
1627 }
1628
1629 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1630 {
1631         ADS_STRUCT *ads;
1632         ADS_STATUS rc;
1633         const char *servername, *printername;
1634         struct cli_state *cli = NULL;
1635         struct rpc_pipe_client *pipe_hnd = NULL;
1636         struct sockaddr_storage server_ss;
1637         NTSTATUS nt_status;
1638         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1639         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1640         char *prt_dn, *srv_dn, **srv_cn;
1641         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1642         LDAPMessage *res = NULL;
1643
1644         if (argc < 1 || c->display_usage) {
1645                 d_printf(_("Usage:\n"
1646                            "net ads printer publish <printername> [servername]\n"
1647                            "  Publish printer in AD\n"
1648                            "    printername\tName of the printer\n"
1649                            "    servername\tName of the print server\n"));
1650                 talloc_destroy(mem_ctx);
1651                 return -1;
1652         }
1653
1654         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1655                 talloc_destroy(mem_ctx);
1656                 return -1;
1657         }
1658
1659         printername = argv[0];
1660
1661         if (argc == 2) {
1662                 servername = argv[1];
1663         } else {
1664                 servername = global_myname();
1665         }
1666
1667         /* Get printer data from SPOOLSS */
1668
1669         resolve_name(servername, &server_ss, 0x20, false);
1670
1671         nt_status = cli_full_connection(&cli, global_myname(), servername,
1672                                         &server_ss, 0,
1673                                         "IPC$", "IPC",
1674                                         c->opt_user_name, c->opt_workgroup,
1675                                         c->opt_password ? c->opt_password : "",
1676                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1677                                         Undefined, NULL);
1678
1679         if (NT_STATUS_IS_ERR(nt_status)) {
1680                 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1681                                     "obtain data for %s\n"),
1682                           servername, printername);
1683                 ads_destroy(&ads);
1684                 talloc_destroy(mem_ctx);
1685                 return -1;
1686         }
1687
1688         /* Publish on AD server */
1689
1690         ads_find_machine_acct(ads, &res, servername);
1691
1692         if (ads_count_replies(ads, res) == 0) {
1693                 d_fprintf(stderr, _("Could not find machine account for server "
1694                                     "%s\n"),
1695                          servername);
1696                 ads_destroy(&ads);
1697                 talloc_destroy(mem_ctx);
1698                 return -1;
1699         }
1700
1701         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1702         srv_cn = ldap_explode_dn(srv_dn, 1);
1703
1704         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1705         printername_escaped = escape_rdn_val_string_alloc(printername);
1706         if (!srv_cn_escaped || !printername_escaped) {
1707                 SAFE_FREE(srv_cn_escaped);
1708                 SAFE_FREE(printername_escaped);
1709                 d_fprintf(stderr, _("Internal error, out of memory!"));
1710                 ads_destroy(&ads);
1711                 talloc_destroy(mem_ctx);
1712                 return -1;
1713         }
1714
1715         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1716                 SAFE_FREE(srv_cn_escaped);
1717                 SAFE_FREE(printername_escaped);
1718                 d_fprintf(stderr, _("Internal error, out of memory!"));
1719                 ads_destroy(&ads);
1720                 talloc_destroy(mem_ctx);
1721                 return -1;
1722         }
1723
1724         SAFE_FREE(srv_cn_escaped);
1725         SAFE_FREE(printername_escaped);
1726
1727         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1728         if (!NT_STATUS_IS_OK(nt_status)) {
1729                 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1730                          servername);
1731                 SAFE_FREE(prt_dn);
1732                 ads_destroy(&ads);
1733                 talloc_destroy(mem_ctx);
1734                 return -1;
1735         }
1736
1737         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1738                                                               printername))) {
1739                 SAFE_FREE(prt_dn);
1740                 ads_destroy(&ads);
1741                 talloc_destroy(mem_ctx);
1742                 return -1;
1743         }
1744
1745         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1746         if (!ADS_ERR_OK(rc)) {
1747                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1748                 SAFE_FREE(prt_dn);
1749                 ads_destroy(&ads);
1750                 talloc_destroy(mem_ctx);
1751                 return -1;
1752         }
1753
1754         d_printf("published printer\n");
1755         SAFE_FREE(prt_dn);
1756         ads_destroy(&ads);
1757         talloc_destroy(mem_ctx);
1758
1759         return 0;
1760 }
1761
1762 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1763 {
1764         ADS_STRUCT *ads;
1765         ADS_STATUS rc;
1766         const char *servername;
1767         char *prt_dn;
1768         LDAPMessage *res = NULL;
1769
1770         if (argc < 1 || c->display_usage) {
1771                 d_printf(_("Usage:\n"
1772                            "net ads printer remove <printername> [servername]\n"
1773                            "  Remove a printer from the AD\n"
1774                            "    printername\tName of the printer\n"
1775                            "    servername\tName of the print server\n"));
1776                 return -1;
1777         }
1778
1779         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1780                 return -1;
1781         }
1782
1783         if (argc > 1) {
1784                 servername = argv[1];
1785         } else {
1786                 servername = global_myname();
1787         }
1788
1789         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1790
1791         if (!ADS_ERR_OK(rc)) {
1792                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1793                 ads_msgfree(ads, res);
1794                 ads_destroy(&ads);
1795                 return -1;
1796         }
1797
1798         if (ads_count_replies(ads, res) == 0) {
1799                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1800                 ads_msgfree(ads, res);
1801                 ads_destroy(&ads);
1802                 return -1;
1803         }
1804
1805         prt_dn = ads_get_dn(ads, talloc_tos(), res);
1806         ads_msgfree(ads, res);
1807         rc = ads_del_dn(ads, prt_dn);
1808         TALLOC_FREE(prt_dn);
1809
1810         if (!ADS_ERR_OK(rc)) {
1811                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1812                 ads_destroy(&ads);
1813                 return -1;
1814         }
1815
1816         ads_destroy(&ads);
1817         return 0;
1818 }
1819
1820 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1821 {
1822         struct functable func[] = {
1823                 {
1824                         "search",
1825                         net_ads_printer_search,
1826                         NET_TRANSPORT_ADS,
1827                         N_("Search for a printer"),
1828                         N_("net ads printer search\n"
1829                            "    Search for a printer")
1830                 },
1831                 {
1832                         "info",
1833                         net_ads_printer_info,
1834                         NET_TRANSPORT_ADS,
1835                         N_("Display printer information"),
1836                         N_("net ads printer info\n"
1837                            "    Display printer information")
1838                 },
1839                 {
1840                         "publish",
1841                         net_ads_printer_publish,
1842                         NET_TRANSPORT_ADS,
1843                         N_("Publish a printer"),
1844                         N_("net ads printer publish\n"
1845                            "    Publish a printer")
1846                 },
1847                 {
1848                         "remove",
1849                         net_ads_printer_remove,
1850                         NET_TRANSPORT_ADS,
1851                         N_("Delete a printer"),
1852                         N_("net ads printer remove\n"
1853                            "    Delete a printer")
1854                 },
1855                 {NULL, NULL, 0, NULL, NULL}
1856         };
1857
1858         return net_run_function(c, argc, argv, "net ads printer", func);
1859 }
1860
1861
1862 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1863 {
1864         ADS_STRUCT *ads;
1865         const char *auth_principal = c->opt_user_name;
1866         const char *auth_password = c->opt_password;
1867         char *realm = NULL;
1868         char *new_password = NULL;
1869         char *chr, *prompt;
1870         const char *user;
1871         ADS_STATUS ret;
1872
1873         if (c->display_usage) {
1874                 d_printf(_("Usage:\n"
1875                            "net ads password <username>\n"
1876                            "  Change password for user\n"
1877                            "    username\tName of user to change password for\n"));
1878                 return 0;
1879         }
1880
1881         if (c->opt_user_name == NULL || c->opt_password == NULL) {
1882                 d_fprintf(stderr, _("You must supply an administrator "
1883                                     "username/password\n"));
1884                 return -1;
1885         }
1886
1887         if (argc < 1) {
1888                 d_fprintf(stderr, _("ERROR: You must say which username to "
1889                                     "change password for\n"));
1890                 return -1;
1891         }
1892
1893         user = argv[0];
1894         if (!strchr_m(user, '@')) {
1895                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1896                         return -1;
1897                 }
1898                 user = chr;
1899         }
1900
1901         use_in_memory_ccache();
1902         chr = strchr_m(auth_principal, '@');
1903         if (chr) {
1904                 realm = ++chr;
1905         } else {
1906                 realm = lp_realm();
1907         }
1908
1909         /* use the realm so we can eventually change passwords for users
1910         in realms other than default */
1911         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1912                 return -1;
1913         }
1914
1915         /* we don't actually need a full connect, but it's the easy way to
1916                 fill in the KDC's addresss */
1917         ads_connect(ads);
1918
1919         if (!ads->config.realm) {
1920                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1921                 ads_destroy(&ads);
1922                 return -1;
1923         }
1924
1925         if (argv[1]) {
1926                 new_password = (char *)argv[1];
1927         } else {
1928                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1929                         return -1;
1930                 }
1931                 new_password = getpass(prompt);
1932                 free(prompt);
1933         }
1934
1935         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1936                                 auth_password, user, new_password, ads->auth.time_offset);
1937         if (!ADS_ERR_OK(ret)) {
1938                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1939                 ads_destroy(&ads);
1940                 return -1;
1941         }
1942
1943         d_printf(_("Password change for %s completed.\n"), user);
1944         ads_destroy(&ads);
1945
1946         return 0;
1947 }
1948
1949 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1950 {
1951         ADS_STRUCT *ads;
1952         char *host_principal;
1953         fstring my_name;
1954         ADS_STATUS ret;
1955
1956         if (c->display_usage) {
1957                 d_printf(_("Usage:\n"
1958                            "net ads changetrustpw\n"
1959                            "    Change the machine account's trust password\n"));
1960                 return 0;
1961         }
1962
1963         if (!secrets_init()) {
1964                 DEBUG(1,("Failed to initialise secrets database\n"));
1965                 return -1;
1966         }
1967
1968         net_use_krb_machine_account(c);
1969
1970         use_in_memory_ccache();
1971
1972         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1973                 return -1;
1974         }
1975
1976         fstrcpy(my_name, global_myname());
1977         strlower_m(my_name);
1978         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1979                 ads_destroy(&ads);
1980                 return -1;
1981         }
1982         d_printf(_("Changing password for principal: %s\n"), host_principal);
1983
1984         ret = ads_change_trust_account_password(ads, host_principal);
1985
1986         if (!ADS_ERR_OK(ret)) {
1987                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1988                 ads_destroy(&ads);
1989                 SAFE_FREE(host_principal);
1990                 return -1;
1991         }
1992
1993         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
1994
1995         if (USE_SYSTEM_KEYTAB) {
1996                 d_printf(_("Attempting to update system keytab with new password.\n"));
1997                 if (ads_keytab_create_default(ads)) {
1998                         d_printf(_("Failed to update system keytab.\n"));
1999                 }
2000         }
2001
2002         ads_destroy(&ads);
2003         SAFE_FREE(host_principal);
2004
2005         return 0;
2006 }
2007
2008 /*
2009   help for net ads search
2010 */
2011 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2012 {
2013         d_printf(_(
2014                 "\nnet ads search <expression> <attributes...>\n"
2015                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2016                 "The expression is a standard LDAP search expression, and the\n"
2017                 "attributes are a list of LDAP fields to show in the results.\n\n"
2018                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2019                 ));
2020         net_common_flags_usage(c, argc, argv);
2021         return -1;
2022 }
2023
2024
2025 /*
2026   general ADS search function. Useful in diagnosing problems in ADS
2027 */
2028 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2029 {
2030         ADS_STRUCT *ads;
2031         ADS_STATUS rc;
2032         const char *ldap_exp;
2033         const char **attrs;
2034         LDAPMessage *res = NULL;
2035
2036         if (argc < 1 || c->display_usage) {
2037                 return net_ads_search_usage(c, argc, argv);
2038         }
2039
2040         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2041                 return -1;
2042         }
2043
2044         ldap_exp = argv[0];
2045         attrs = (argv + 1);
2046
2047         rc = ads_do_search_all(ads, ads->config.bind_path,
2048                                LDAP_SCOPE_SUBTREE,
2049                                ldap_exp, attrs, &res);
2050         if (!ADS_ERR_OK(rc)) {
2051                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2052                 ads_destroy(&ads);
2053                 return -1;
2054         }
2055
2056         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2057
2058         /* dump the results */
2059         ads_dump(ads, res);
2060
2061         ads_msgfree(ads, res);
2062         ads_destroy(&ads);
2063
2064         return 0;
2065 }
2066
2067
2068 /*
2069   help for net ads search
2070 */
2071 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2072 {
2073         d_printf(_(
2074                 "\nnet ads dn <dn> <attributes...>\n"
2075                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2076                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2077                 "to show in the results\n\n"
2078                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2079                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2080                 ));
2081         net_common_flags_usage(c, argc, argv);
2082         return -1;
2083 }
2084
2085
2086 /*
2087   general ADS search function. Useful in diagnosing problems in ADS
2088 */
2089 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2090 {
2091         ADS_STRUCT *ads;
2092         ADS_STATUS rc;
2093         const char *dn;
2094         const char **attrs;
2095         LDAPMessage *res = NULL;
2096
2097         if (argc < 1 || c->display_usage) {
2098                 return net_ads_dn_usage(c, argc, argv);
2099         }
2100
2101         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2102                 return -1;
2103         }
2104
2105         dn = argv[0];
2106         attrs = (argv + 1);
2107
2108         rc = ads_do_search_all(ads, dn,
2109                                LDAP_SCOPE_BASE,
2110                                "(objectclass=*)", attrs, &res);
2111         if (!ADS_ERR_OK(rc)) {
2112                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2113                 ads_destroy(&ads);
2114                 return -1;
2115         }
2116
2117         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2118
2119         /* dump the results */
2120         ads_dump(ads, res);
2121
2122         ads_msgfree(ads, res);
2123         ads_destroy(&ads);
2124
2125         return 0;
2126 }
2127
2128 /*
2129   help for net ads sid search
2130 */
2131 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2132 {
2133         d_printf(_(
2134                 "\nnet ads sid <sid> <attributes...>\n"
2135                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2136                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2137                 "to show in the results\n\n"
2138                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2139                 ));
2140         net_common_flags_usage(c, argc, argv);
2141         return -1;
2142 }
2143
2144
2145 /*
2146   general ADS search function. Useful in diagnosing problems in ADS
2147 */
2148 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2149 {
2150         ADS_STRUCT *ads;
2151         ADS_STATUS rc;
2152         const char *sid_string;
2153         const char **attrs;
2154         LDAPMessage *res = NULL;
2155         DOM_SID sid;
2156
2157         if (argc < 1 || c->display_usage) {
2158                 return net_ads_sid_usage(c, argc, argv);
2159         }
2160
2161         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2162                 return -1;
2163         }
2164
2165         sid_string = argv[0];
2166         attrs = (argv + 1);
2167
2168         if (!string_to_sid(&sid, sid_string)) {
2169                 d_fprintf(stderr, _("could not convert sid\n"));
2170                 ads_destroy(&ads);
2171                 return -1;
2172         }
2173
2174         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2175         if (!ADS_ERR_OK(rc)) {
2176                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2177                 ads_destroy(&ads);
2178                 return -1;
2179         }
2180
2181         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2182
2183         /* dump the results */
2184         ads_dump(ads, res);
2185
2186         ads_msgfree(ads, res);
2187         ads_destroy(&ads);
2188
2189         return 0;
2190 }
2191
2192 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2193 {
2194         int ret;
2195         ADS_STRUCT *ads;
2196
2197         if (c->display_usage) {
2198                 d_printf(_("Usage:\n"
2199                            "net ads keytab flush\n"
2200                            "    Delete the whole keytab\n"));
2201                 return 0;
2202         }
2203
2204         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2205                 return -1;
2206         }
2207         ret = ads_keytab_flush(ads);
2208         ads_destroy(&ads);
2209         return ret;
2210 }
2211
2212 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2213 {
2214         int i;
2215         int ret = 0;
2216         ADS_STRUCT *ads;
2217
2218         if (c->display_usage) {
2219                 d_printf(_("Usage:\n"
2220                            "net ads keytab add <principal> [principal ...]\n"
2221                            "  Add principals to local keytab\n"
2222                            "    principal\tKerberos principal to add to "
2223                            "keytab\n"));
2224                 return 0;
2225         }
2226
2227         d_printf(_("Processing principals to add...\n"));
2228         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2229                 return -1;
2230         }
2231         for (i = 0; i < argc; i++) {
2232                 ret |= ads_keytab_add_entry(ads, argv[i]);
2233         }
2234         ads_destroy(&ads);
2235         return ret;
2236 }
2237
2238 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2239 {
2240         ADS_STRUCT *ads;
2241         int ret;
2242
2243         if (c->display_usage) {
2244                 d_printf(_("Usage:\n"
2245                            "net ads keytab create\n"
2246                            "    Create new default keytab\n"));
2247                 return 0;
2248         }
2249
2250         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2251                 return -1;
2252         }
2253         ret = ads_keytab_create_default(ads);
2254         ads_destroy(&ads);
2255         return ret;
2256 }
2257
2258 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2259 {
2260         const char *keytab = NULL;
2261
2262         if (c->display_usage) {
2263                 d_printf(_("Usage:\n"
2264                            "net ads keytab list [keytab]\n"
2265                            "  List a local keytab\n"
2266                            "    keytab\tKeytab to list\n"));
2267                 return 0;
2268         }
2269
2270         if (argc >= 1) {
2271                 keytab = argv[0];
2272         }
2273
2274         return ads_keytab_list(keytab);
2275 }
2276
2277
2278 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2279 {
2280         struct functable func[] = {
2281                 {
2282                         "add",
2283                         net_ads_keytab_add,
2284                         NET_TRANSPORT_ADS,
2285                         N_("Add a service principal"),
2286                         N_("net ads keytab add\n"
2287                            "    Add a service principal")
2288                 },
2289                 {
2290                         "create",
2291                         net_ads_keytab_create,
2292                         NET_TRANSPORT_ADS,
2293                         N_("Create a fresh keytab"),
2294                         N_("net ads keytab create\n"
2295                            "    Create a fresh keytab")
2296                 },
2297                 {
2298                         "flush",
2299                         net_ads_keytab_flush,
2300                         NET_TRANSPORT_ADS,
2301                         N_("Remove all keytab entries"),
2302                         N_("net ads keytab flush\n"
2303                            "    Remove all keytab entries")
2304                 },
2305                 {
2306                         "list",
2307                         net_ads_keytab_list,
2308                         NET_TRANSPORT_ADS,
2309                         N_("List a keytab"),
2310                         N_("net ads keytab list\n"
2311                            "    List a keytab")
2312                 },
2313                 {NULL, NULL, 0, NULL, NULL}
2314         };
2315
2316         if (!USE_KERBEROS_KEYTAB) {
2317                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2318                     "keytab method to use keytab functions.\n"));
2319         }
2320
2321         return net_run_function(c, argc, argv, "net ads keytab", func);
2322 }
2323
2324 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2325 {
2326         int ret = -1;
2327
2328         if (c->display_usage) {
2329                 d_printf(_("Usage:\n"
2330                            "net ads kerberos renew\n"
2331                            "    Renew TGT from existing credential cache\n"));
2332                 return 0;
2333         }
2334
2335         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2336         if (ret) {
2337                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2338                         error_message(ret));
2339         }
2340         return ret;
2341 }
2342
2343 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2344 {
2345         struct PAC_DATA *pac = NULL;
2346         struct PAC_LOGON_INFO *info = NULL;
2347         TALLOC_CTX *mem_ctx = NULL;
2348         NTSTATUS status;
2349         int ret = -1;
2350         const char *impersonate_princ_s = NULL;
2351
2352         if (c->display_usage) {
2353                 d_printf(_("Usage:\n"
2354                            "net ads kerberos pac\n"
2355                            "    Dump the Kerberos PAC\n"));
2356                 return 0;
2357         }
2358
2359         mem_ctx = talloc_init("net_ads_kerberos_pac");
2360         if (!mem_ctx) {
2361                 goto out;
2362         }
2363
2364         if (argc > 0) {
2365                 impersonate_princ_s = argv[0];
2366         }
2367
2368         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2369
2370         status = kerberos_return_pac(mem_ctx,
2371                                      c->opt_user_name,
2372                                      c->opt_password,
2373                                      0,
2374                                      NULL,
2375                                      NULL,
2376                                      NULL,
2377                                      true,
2378                                      true,
2379                                      2592000, /* one month */
2380                                      impersonate_princ_s,
2381                                      &pac);
2382         if (!NT_STATUS_IS_OK(status)) {
2383                 d_printf(_("failed to query kerberos PAC: %s\n"),
2384                         nt_errstr(status));
2385                 goto out;
2386         }
2387
2388         info = get_logon_info_from_pac(pac);
2389         if (info) {
2390                 const char *s;
2391                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2392                 d_printf(_("The Pac: %s\n"), s);
2393         }
2394
2395         ret = 0;
2396  out:
2397         TALLOC_FREE(mem_ctx);
2398         return ret;
2399 }
2400
2401 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2402 {
2403         TALLOC_CTX *mem_ctx = NULL;
2404         int ret = -1;
2405         NTSTATUS status;
2406
2407         if (c->display_usage) {
2408                 d_printf(_("Usage:\n"
2409                            "net ads kerberos kinit\n"
2410                            "    Get Ticket Granting Ticket (TGT) for the user\n"));
2411                 return 0;
2412         }
2413
2414         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2415         if (!mem_ctx) {
2416                 goto out;
2417         }
2418
2419         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2420
2421         ret = kerberos_kinit_password_ext(c->opt_user_name,
2422                                           c->opt_password,
2423                                           0,
2424                                           NULL,
2425                                           NULL,
2426                                           NULL,
2427                                           true,
2428                                           true,
2429                                           2592000, /* one month */
2430                                           &status);
2431         if (ret) {
2432                 d_printf(_("failed to kinit password: %s\n"),
2433                         nt_errstr(status));
2434         }
2435  out:
2436         return ret;
2437 }
2438
2439 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2440 {
2441         struct functable func[] = {
2442                 {
2443                         "kinit",
2444                         net_ads_kerberos_kinit,
2445                         NET_TRANSPORT_ADS,
2446                         N_("Retrieve Ticket Granting Ticket (TGT)"),
2447                         N_("net ads kerberos kinit\n"
2448                            "    Receive Ticket Granting Ticket (TGT)")
2449                 },
2450                 {
2451                         "renew",
2452                         net_ads_kerberos_renew,
2453                         NET_TRANSPORT_ADS,
2454                         N_("Renew Ticket Granting Ticket from credential cache"),
2455                         N_("net ads kerberos renew\n"
2456                            "    Renew Ticket Granting Ticket (TGT) from "
2457                            "credential cache")
2458                 },
2459                 {
2460                         "pac",
2461                         net_ads_kerberos_pac,
2462                         NET_TRANSPORT_ADS,
2463                         N_("Dump Kerberos PAC"),
2464                         N_("net ads kerberos pac\n"
2465                            "    Dump Kerberos PAC")
2466                 },
2467                 {NULL, NULL, 0, NULL, NULL}
2468         };
2469
2470         return net_run_function(c, argc, argv, "net ads kerberos", func);
2471 }
2472
2473 int net_ads(struct net_context *c, int argc, const char **argv)
2474 {
2475         struct functable func[] = {
2476                 {
2477                         "info",
2478                         net_ads_info,
2479                         NET_TRANSPORT_ADS,
2480                         N_("Display details on remote ADS server"),
2481                         N_("net ads info\n"
2482                            "    Display details on remote ADS server")
2483                 },
2484                 {
2485                         "join",
2486                         net_ads_join,
2487                         NET_TRANSPORT_ADS,
2488                         N_("Join the local machine to ADS realm"),
2489                         N_("net ads join\n"
2490                            "    Join the local machine to ADS realm")
2491                 },
2492                 {
2493                         "testjoin",
2494                         net_ads_testjoin,
2495                         NET_TRANSPORT_ADS,
2496                         N_("Validate machine account"),
2497                         N_("net ads testjoin\n"
2498                            "    Validate machine account")
2499                 },
2500                 {
2501                         "leave",
2502                         net_ads_leave,
2503                         NET_TRANSPORT_ADS,
2504                         N_("Remove the local machine from ADS"),
2505                         N_("net ads leave\n"
2506                            "    Remove the local machine from ADS")
2507                 },
2508                 {
2509                         "status",
2510                         net_ads_status,
2511                         NET_TRANSPORT_ADS,
2512                         N_("Display machine account details"),
2513                         N_("net ads status\n"
2514                            "    Display machine account details")
2515                 },
2516                 {
2517                         "user",
2518                         net_ads_user,
2519                         NET_TRANSPORT_ADS,
2520                         N_("List/modify users"),
2521                         N_("net ads user\n"
2522                            "    List/modify users")
2523                 },
2524                 {
2525                         "group",
2526                         net_ads_group,
2527                         NET_TRANSPORT_ADS,
2528                         N_("List/modify groups"),
2529                         N_("net ads group\n"
2530                            "    List/modify groups")
2531                 },
2532                 {
2533                         "dns",
2534                         net_ads_dns,
2535                         NET_TRANSPORT_ADS,
2536                         N_("Issue dynamic DNS update"),
2537                         N_("net ads dns\n"
2538                            "    Issue dynamic DNS update")
2539                 },
2540                 {
2541                         "password",
2542                         net_ads_password,
2543                         NET_TRANSPORT_ADS,
2544                         N_("Change user passwords"),
2545                         N_("net ads password\n"
2546                            "    Change user passwords")
2547                 },
2548                 {
2549                         "changetrustpw",
2550                         net_ads_changetrustpw,
2551                         NET_TRANSPORT_ADS,
2552                         N_("Change trust account password"),
2553                         N_("net ads changetrustpw\n"
2554                            "    Change trust account password")
2555                 },
2556                 {
2557                         "printer",
2558                         net_ads_printer,
2559                         NET_TRANSPORT_ADS,
2560                         N_("List/modify printer entries"),
2561                         N_("net ads printer\n"
2562                            "    List/modify printer entries")
2563                 },
2564                 {
2565                         "search",
2566                         net_ads_search,
2567                         NET_TRANSPORT_ADS,
2568                         N_("Issue LDAP search using filter"),
2569                         N_("net ads search\n"
2570                            "    Issue LDAP search using filter")
2571                 },
2572                 {
2573                         "dn",
2574                         net_ads_dn,
2575                         NET_TRANSPORT_ADS,
2576                         N_("Issue LDAP search by DN"),
2577                         N_("net ads dn\n"
2578                            "    Issue LDAP search by DN")
2579                 },
2580                 {
2581                         "sid",
2582                         net_ads_sid,
2583                         NET_TRANSPORT_ADS,
2584                         N_("Issue LDAP search by SID"),
2585                         N_("net ads sid\n"
2586                            "    Issue LDAP search by SID")
2587                 },
2588                 {
2589                         "workgroup",
2590                         net_ads_workgroup,
2591                         NET_TRANSPORT_ADS,
2592                         N_("Display workgroup name"),
2593                         N_("net ads workgroup\n"
2594                            "    Display the workgroup name")
2595                 },
2596                 {
2597                         "lookup",
2598                         net_ads_lookup,
2599                         NET_TRANSPORT_ADS,
2600                         N_("Perfom CLDAP query on DC"),
2601                         N_("net ads lookup\n"
2602                            "    Find the ADS DC using CLDAP lookups")
2603                 },
2604                 {
2605                         "keytab",
2606                         net_ads_keytab,
2607                         NET_TRANSPORT_ADS,
2608                         N_("Manage local keytab file"),
2609                         N_("net ads keytab\n"
2610                            "    Manage local keytab file")
2611                 },
2612                 {
2613                         "gpo",
2614                         net_ads_gpo,
2615                         NET_TRANSPORT_ADS,
2616                         N_("Manage group policy objects"),
2617                         N_("net ads gpo\n"
2618                            "    Manage group policy objects")
2619                 },
2620                 {
2621                         "kerberos",
2622                         net_ads_kerberos,
2623                         NET_TRANSPORT_ADS,
2624                         N_("Manage kerberos keytab"),
2625                         N_("net ads kerberos\n"
2626                            "    Manage kerberos keytab")
2627                 },
2628                 {NULL, NULL, 0, NULL, NULL}
2629         };
2630
2631         return net_run_function(c, argc, argv, "net ads", func);
2632 }
2633
2634 #else
2635
2636 static int net_ads_noads(void)
2637 {
2638         d_fprintf(stderr, _("ADS support not compiled in\n"));
2639         return -1;
2640 }
2641
2642 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2643 {
2644         return net_ads_noads();
2645 }
2646
2647 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2648 {
2649         return net_ads_noads();
2650 }
2651
2652 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2653 {
2654         return net_ads_noads();
2655 }
2656
2657 int net_ads_join(struct net_context *c, int argc, const char **argv)
2658 {
2659         return net_ads_noads();
2660 }
2661
2662 int net_ads_user(struct net_context *c, int argc, const char **argv)
2663 {
2664         return net_ads_noads();
2665 }
2666
2667 int net_ads_group(struct net_context *c, int argc, const char **argv)
2668 {
2669         return net_ads_noads();
2670 }
2671
2672 /* this one shouldn't display a message */
2673 int net_ads_check(struct net_context *c)
2674 {
2675         return -1;
2676 }
2677
2678 int net_ads_check_our_domain(struct net_context *c)
2679 {
2680         return -1;
2681 }
2682
2683 int net_ads(struct net_context *c, int argc, const char **argv)
2684 {
2685         return net_ads_noads();
2686 }
2687
2688 #endif  /* WITH_ADS */