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