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