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