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