s3-net: fix net ads dns usage calls.
[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(  "%s\n"
1436                            "net ads dns register\n"
1437                            "    %s\n",
1438                          _("Usage:"),
1439                          _("Register hostname with DNS\n"));
1440                 return -1;
1441         }
1442
1443         if (!(ctx = talloc_init("net_ads_dns"))) {
1444                 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1445                 return -1;
1446         }
1447
1448         status = ads_startup(c, true, &ads);
1449         if ( !ADS_ERR_OK(status) ) {
1450                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1451                 TALLOC_FREE(ctx);
1452                 return -1;
1453         }
1454
1455         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1456                 d_fprintf( stderr, _("DNS update failed!\n") );
1457                 ads_destroy( &ads );
1458                 TALLOC_FREE( ctx );
1459                 return -1;
1460         }
1461
1462         d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1463
1464         ads_destroy(&ads);
1465         TALLOC_FREE( ctx );
1466
1467         return 0;
1468 #else
1469         d_fprintf(stderr,
1470                   _("DNS update support not enabled at compile time!\n"));
1471         return -1;
1472 #endif
1473 }
1474
1475 #if defined(WITH_DNS_UPDATES)
1476 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1477 #endif
1478
1479 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1480 {
1481 #if defined(WITH_DNS_UPDATES)
1482         DNS_ERROR err;
1483
1484 #ifdef DEVELOPER
1485         talloc_enable_leak_report();
1486 #endif
1487
1488         if (argc != 2 || c->display_usage) {
1489                 d_printf(  "%s\n"
1490                            "    %s\n"
1491                            "    %s\n",
1492                          _("Usage:"),
1493                          _("net ads dns gethostbyname <server> <name>\n"),
1494                          _("  Look up hostname from the AD\n"
1495                            "    server\tName server to use\n"
1496                            "    name\tName to look up\n"));
1497                 return -1;
1498         }
1499
1500         err = do_gethostbyname(argv[0], argv[1]);
1501
1502         d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1503 #endif
1504         return 0;
1505 }
1506
1507 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1508 {
1509         struct functable func[] = {
1510                 {
1511                         "register",
1512                         net_ads_dns_register,
1513                         NET_TRANSPORT_ADS,
1514                         N_("Add host dns entry to AD"),
1515                         N_("net ads dns register\n"
1516                            "    Add host dns entry to AD")
1517                 },
1518                 {
1519                         "gethostbyname",
1520                         net_ads_dns_gethostbyname,
1521                         NET_TRANSPORT_ADS,
1522                         N_("Look up host"),
1523                         N_("net ads dns gethostbyname\n"
1524                            "    Look up host")
1525                 },
1526                 {NULL, NULL, 0, NULL, NULL}
1527         };
1528
1529         return net_run_function(c, argc, argv, "net ads dns", func);
1530 }
1531
1532 /*******************************************************************
1533  ********************************************************************/
1534
1535 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1536 {
1537         d_printf(_(
1538 "\nnet ads printer search <printer>"
1539 "\n\tsearch for a printer in the directory\n"
1540 "\nnet ads printer info <printer> <server>"
1541 "\n\tlookup info in directory for printer on server"
1542 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1543 "\nnet ads printer publish <printername>"
1544 "\n\tpublish printer in directory"
1545 "\n\t(note: printer name is required)\n"
1546 "\nnet ads printer remove <printername>"
1547 "\n\tremove printer from directory"
1548 "\n\t(note: printer name is required)\n"));
1549         return -1;
1550 }
1551
1552 /*******************************************************************
1553  ********************************************************************/
1554
1555 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1556 {
1557         ADS_STRUCT *ads;
1558         ADS_STATUS rc;
1559         LDAPMessage *res = NULL;
1560
1561         if (c->display_usage) {
1562                 d_printf(  "%s\n"
1563                            "net ads printer search\n"
1564                            "    %s\n",
1565                          _("Usage:"),
1566                          _("List printers in the AD"));
1567                 return 0;
1568         }
1569
1570         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1571                 return -1;
1572         }
1573
1574         rc = ads_find_printers(ads, &res);
1575
1576         if (!ADS_ERR_OK(rc)) {
1577                 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1578                 ads_msgfree(ads, res);
1579                 ads_destroy(&ads);
1580                 return -1;
1581         }
1582
1583         if (ads_count_replies(ads, res) == 0) {
1584                 d_fprintf(stderr, _("No results found\n"));
1585                 ads_msgfree(ads, res);
1586                 ads_destroy(&ads);
1587                 return -1;
1588         }
1589
1590         ads_dump(ads, res);
1591         ads_msgfree(ads, res);
1592         ads_destroy(&ads);
1593         return 0;
1594 }
1595
1596 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1597 {
1598         ADS_STRUCT *ads;
1599         ADS_STATUS rc;
1600         const char *servername, *printername;
1601         LDAPMessage *res = NULL;
1602
1603         if (c->display_usage) {
1604                 d_printf("%s\n%s",
1605                          _("Usage:"),
1606                          _("net ads printer info [printername [servername]]\n"
1607                            "  Display printer info from AD\n"
1608                            "    printername\tPrinter name or wildcard\n"
1609                            "    servername\tName of the print server\n"));
1610                 return 0;
1611         }
1612
1613         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1614                 return -1;
1615         }
1616
1617         if (argc > 0) {
1618                 printername = argv[0];
1619         } else {
1620                 printername = "*";
1621         }
1622
1623         if (argc > 1) {
1624                 servername =  argv[1];
1625         } else {
1626                 servername = global_myname();
1627         }
1628
1629         rc = ads_find_printer_on_server(ads, &res, printername, servername);
1630
1631         if (!ADS_ERR_OK(rc)) {
1632                 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1633                         servername, ads_errstr(rc));
1634                 ads_msgfree(ads, res);
1635                 ads_destroy(&ads);
1636                 return -1;
1637         }
1638
1639         if (ads_count_replies(ads, res) == 0) {
1640                 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1641                 ads_msgfree(ads, res);
1642                 ads_destroy(&ads);
1643                 return -1;
1644         }
1645
1646         ads_dump(ads, res);
1647         ads_msgfree(ads, res);
1648         ads_destroy(&ads);
1649
1650         return 0;
1651 }
1652
1653 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1654 {
1655         ADS_STRUCT *ads;
1656         ADS_STATUS rc;
1657         const char *servername, *printername;
1658         struct cli_state *cli = NULL;
1659         struct rpc_pipe_client *pipe_hnd = NULL;
1660         struct sockaddr_storage server_ss;
1661         NTSTATUS nt_status;
1662         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1663         ADS_MODLIST mods = ads_init_mods(mem_ctx);
1664         char *prt_dn, *srv_dn, **srv_cn;
1665         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1666         LDAPMessage *res = NULL;
1667
1668         if (argc < 1 || c->display_usage) {
1669                 d_printf("%s\n%s",
1670                          _("Usage:"),
1671                          _("net ads printer publish <printername> [servername]\n"
1672                            "  Publish printer in AD\n"
1673                            "    printername\tName of the printer\n"
1674                            "    servername\tName of the print server\n"));
1675                 talloc_destroy(mem_ctx);
1676                 return -1;
1677         }
1678
1679         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1680                 talloc_destroy(mem_ctx);
1681                 return -1;
1682         }
1683
1684         printername = argv[0];
1685
1686         if (argc == 2) {
1687                 servername = argv[1];
1688         } else {
1689                 servername = global_myname();
1690         }
1691
1692         /* Get printer data from SPOOLSS */
1693
1694         resolve_name(servername, &server_ss, 0x20, false);
1695
1696         nt_status = cli_full_connection(&cli, global_myname(), servername,
1697                                         &server_ss, 0,
1698                                         "IPC$", "IPC",
1699                                         c->opt_user_name, c->opt_workgroup,
1700                                         c->opt_password ? c->opt_password : "",
1701                                         CLI_FULL_CONNECTION_USE_KERBEROS,
1702                                         Undefined, NULL);
1703
1704         if (NT_STATUS_IS_ERR(nt_status)) {
1705                 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1706                                     "obtain data for %s\n"),
1707                           servername, printername);
1708                 ads_destroy(&ads);
1709                 talloc_destroy(mem_ctx);
1710                 return -1;
1711         }
1712
1713         /* Publish on AD server */
1714
1715         ads_find_machine_acct(ads, &res, servername);
1716
1717         if (ads_count_replies(ads, res) == 0) {
1718                 d_fprintf(stderr, _("Could not find machine account for server "
1719                                     "%s\n"),
1720                          servername);
1721                 ads_destroy(&ads);
1722                 talloc_destroy(mem_ctx);
1723                 return -1;
1724         }
1725
1726         srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1727         srv_cn = ldap_explode_dn(srv_dn, 1);
1728
1729         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1730         printername_escaped = escape_rdn_val_string_alloc(printername);
1731         if (!srv_cn_escaped || !printername_escaped) {
1732                 SAFE_FREE(srv_cn_escaped);
1733                 SAFE_FREE(printername_escaped);
1734                 d_fprintf(stderr, _("Internal error, out of memory!"));
1735                 ads_destroy(&ads);
1736                 talloc_destroy(mem_ctx);
1737                 return -1;
1738         }
1739
1740         if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1741                 SAFE_FREE(srv_cn_escaped);
1742                 SAFE_FREE(printername_escaped);
1743                 d_fprintf(stderr, _("Internal error, out of memory!"));
1744                 ads_destroy(&ads);
1745                 talloc_destroy(mem_ctx);
1746                 return -1;
1747         }
1748
1749         SAFE_FREE(srv_cn_escaped);
1750         SAFE_FREE(printername_escaped);
1751
1752         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1753         if (!NT_STATUS_IS_OK(nt_status)) {
1754                 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1755                          servername);
1756                 SAFE_FREE(prt_dn);
1757                 ads_destroy(&ads);
1758                 talloc_destroy(mem_ctx);
1759                 return -1;
1760         }
1761
1762         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1763                                                               printername))) {
1764                 SAFE_FREE(prt_dn);
1765                 ads_destroy(&ads);
1766                 talloc_destroy(mem_ctx);
1767                 return -1;
1768         }
1769
1770         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1771         if (!ADS_ERR_OK(rc)) {
1772                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1773                 SAFE_FREE(prt_dn);
1774                 ads_destroy(&ads);
1775                 talloc_destroy(mem_ctx);
1776                 return -1;
1777         }
1778
1779         d_printf("published printer\n");
1780         SAFE_FREE(prt_dn);
1781         ads_destroy(&ads);
1782         talloc_destroy(mem_ctx);
1783
1784         return 0;
1785 }
1786
1787 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1788 {
1789         ADS_STRUCT *ads;
1790         ADS_STATUS rc;
1791         const char *servername;
1792         char *prt_dn;
1793         LDAPMessage *res = NULL;
1794
1795         if (argc < 1 || c->display_usage) {
1796                 d_printf("%s\n%s",
1797                          _("Usage:"),
1798                          _("net ads printer remove <printername> [servername]\n"
1799                            "  Remove a printer from the AD\n"
1800                            "    printername\tName of the printer\n"
1801                            "    servername\tName of the print server\n"));
1802                 return -1;
1803         }
1804
1805         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1806                 return -1;
1807         }
1808
1809         if (argc > 1) {
1810                 servername = argv[1];
1811         } else {
1812                 servername = global_myname();
1813         }
1814
1815         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1816
1817         if (!ADS_ERR_OK(rc)) {
1818                 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1819                 ads_msgfree(ads, res);
1820                 ads_destroy(&ads);
1821                 return -1;
1822         }
1823
1824         if (ads_count_replies(ads, res) == 0) {
1825                 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1826                 ads_msgfree(ads, res);
1827                 ads_destroy(&ads);
1828                 return -1;
1829         }
1830
1831         prt_dn = ads_get_dn(ads, talloc_tos(), res);
1832         ads_msgfree(ads, res);
1833         rc = ads_del_dn(ads, prt_dn);
1834         TALLOC_FREE(prt_dn);
1835
1836         if (!ADS_ERR_OK(rc)) {
1837                 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1838                 ads_destroy(&ads);
1839                 return -1;
1840         }
1841
1842         ads_destroy(&ads);
1843         return 0;
1844 }
1845
1846 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1847 {
1848         struct functable func[] = {
1849                 {
1850                         "search",
1851                         net_ads_printer_search,
1852                         NET_TRANSPORT_ADS,
1853                         N_("Search for a printer"),
1854                         N_("net ads printer search\n"
1855                            "    Search for a printer")
1856                 },
1857                 {
1858                         "info",
1859                         net_ads_printer_info,
1860                         NET_TRANSPORT_ADS,
1861                         N_("Display printer information"),
1862                         N_("net ads printer info\n"
1863                            "    Display printer information")
1864                 },
1865                 {
1866                         "publish",
1867                         net_ads_printer_publish,
1868                         NET_TRANSPORT_ADS,
1869                         N_("Publish a printer"),
1870                         N_("net ads printer publish\n"
1871                            "    Publish a printer")
1872                 },
1873                 {
1874                         "remove",
1875                         net_ads_printer_remove,
1876                         NET_TRANSPORT_ADS,
1877                         N_("Delete a printer"),
1878                         N_("net ads printer remove\n"
1879                            "    Delete a printer")
1880                 },
1881                 {NULL, NULL, 0, NULL, NULL}
1882         };
1883
1884         return net_run_function(c, argc, argv, "net ads printer", func);
1885 }
1886
1887
1888 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1889 {
1890         ADS_STRUCT *ads;
1891         const char *auth_principal = c->opt_user_name;
1892         const char *auth_password = c->opt_password;
1893         char *realm = NULL;
1894         char *new_password = NULL;
1895         char *chr, *prompt;
1896         const char *user;
1897         ADS_STATUS ret;
1898
1899         if (c->display_usage) {
1900                 d_printf("%s\n%s",
1901                          _("Usage:"),
1902                          _("net ads password <username>\n"
1903                            "  Change password for user\n"
1904                            "    username\tName of user to change password for\n"));
1905                 return 0;
1906         }
1907
1908         if (c->opt_user_name == NULL || c->opt_password == NULL) {
1909                 d_fprintf(stderr, _("You must supply an administrator "
1910                                     "username/password\n"));
1911                 return -1;
1912         }
1913
1914         if (argc < 1) {
1915                 d_fprintf(stderr, _("ERROR: You must say which username to "
1916                                     "change password for\n"));
1917                 return -1;
1918         }
1919
1920         user = argv[0];
1921         if (!strchr_m(user, '@')) {
1922                 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1923                         return -1;
1924                 }
1925                 user = chr;
1926         }
1927
1928         use_in_memory_ccache();
1929         chr = strchr_m(auth_principal, '@');
1930         if (chr) {
1931                 realm = ++chr;
1932         } else {
1933                 realm = lp_realm();
1934         }
1935
1936         /* use the realm so we can eventually change passwords for users
1937         in realms other than default */
1938         if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1939                 return -1;
1940         }
1941
1942         /* we don't actually need a full connect, but it's the easy way to
1943                 fill in the KDC's addresss */
1944         ads_connect(ads);
1945
1946         if (!ads->config.realm) {
1947                 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1948                 ads_destroy(&ads);
1949                 return -1;
1950         }
1951
1952         if (argv[1]) {
1953                 new_password = (char *)argv[1];
1954         } else {
1955                 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1956                         return -1;
1957                 }
1958                 new_password = getpass(prompt);
1959                 free(prompt);
1960         }
1961
1962         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1963                                 auth_password, user, new_password, ads->auth.time_offset);
1964         if (!ADS_ERR_OK(ret)) {
1965                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1966                 ads_destroy(&ads);
1967                 return -1;
1968         }
1969
1970         d_printf(_("Password change for %s completed.\n"), user);
1971         ads_destroy(&ads);
1972
1973         return 0;
1974 }
1975
1976 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1977 {
1978         ADS_STRUCT *ads;
1979         char *host_principal;
1980         fstring my_name;
1981         ADS_STATUS ret;
1982
1983         if (c->display_usage) {
1984                 d_printf(  "%s\n"
1985                            "net ads changetrustpw\n"
1986                            "    %s\n",
1987                          _("Usage:"),
1988                          _("Change the machine account's trust password"));
1989                 return 0;
1990         }
1991
1992         if (!secrets_init()) {
1993                 DEBUG(1,("Failed to initialise secrets database\n"));
1994                 return -1;
1995         }
1996
1997         net_use_krb_machine_account(c);
1998
1999         use_in_memory_ccache();
2000
2001         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2002                 return -1;
2003         }
2004
2005         fstrcpy(my_name, global_myname());
2006         strlower_m(my_name);
2007         if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2008                 ads_destroy(&ads);
2009                 return -1;
2010         }
2011         d_printf(_("Changing password for principal: %s\n"), host_principal);
2012
2013         ret = ads_change_trust_account_password(ads, host_principal);
2014
2015         if (!ADS_ERR_OK(ret)) {
2016                 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2017                 ads_destroy(&ads);
2018                 SAFE_FREE(host_principal);
2019                 return -1;
2020         }
2021
2022         d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2023
2024         if (USE_SYSTEM_KEYTAB) {
2025                 d_printf(_("Attempting to update system keytab with new password.\n"));
2026                 if (ads_keytab_create_default(ads)) {
2027                         d_printf(_("Failed to update system keytab.\n"));
2028                 }
2029         }
2030
2031         ads_destroy(&ads);
2032         SAFE_FREE(host_principal);
2033
2034         return 0;
2035 }
2036
2037 /*
2038   help for net ads search
2039 */
2040 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2041 {
2042         d_printf(_(
2043                 "\nnet ads search <expression> <attributes...>\n"
2044                 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2045                 "The expression is a standard LDAP search expression, and the\n"
2046                 "attributes are a list of LDAP fields to show in the results.\n\n"
2047                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2048                 ));
2049         net_common_flags_usage(c, argc, argv);
2050         return -1;
2051 }
2052
2053
2054 /*
2055   general ADS search function. Useful in diagnosing problems in ADS
2056 */
2057 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2058 {
2059         ADS_STRUCT *ads;
2060         ADS_STATUS rc;
2061         const char *ldap_exp;
2062         const char **attrs;
2063         LDAPMessage *res = NULL;
2064
2065         if (argc < 1 || c->display_usage) {
2066                 return net_ads_search_usage(c, argc, argv);
2067         }
2068
2069         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2070                 return -1;
2071         }
2072
2073         ldap_exp = argv[0];
2074         attrs = (argv + 1);
2075
2076         rc = ads_do_search_all(ads, ads->config.bind_path,
2077                                LDAP_SCOPE_SUBTREE,
2078                                ldap_exp, attrs, &res);
2079         if (!ADS_ERR_OK(rc)) {
2080                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2081                 ads_destroy(&ads);
2082                 return -1;
2083         }
2084
2085         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2086
2087         /* dump the results */
2088         ads_dump(ads, res);
2089
2090         ads_msgfree(ads, res);
2091         ads_destroy(&ads);
2092
2093         return 0;
2094 }
2095
2096
2097 /*
2098   help for net ads search
2099 */
2100 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2101 {
2102         d_printf(_(
2103                 "\nnet ads dn <dn> <attributes...>\n"
2104                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2105                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2106                 "to show in the results\n\n"
2107                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2108                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2109                 ));
2110         net_common_flags_usage(c, argc, argv);
2111         return -1;
2112 }
2113
2114
2115 /*
2116   general ADS search function. Useful in diagnosing problems in ADS
2117 */
2118 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2119 {
2120         ADS_STRUCT *ads;
2121         ADS_STATUS rc;
2122         const char *dn;
2123         const char **attrs;
2124         LDAPMessage *res = NULL;
2125
2126         if (argc < 1 || c->display_usage) {
2127                 return net_ads_dn_usage(c, argc, argv);
2128         }
2129
2130         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2131                 return -1;
2132         }
2133
2134         dn = argv[0];
2135         attrs = (argv + 1);
2136
2137         rc = ads_do_search_all(ads, dn,
2138                                LDAP_SCOPE_BASE,
2139                                "(objectclass=*)", attrs, &res);
2140         if (!ADS_ERR_OK(rc)) {
2141                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2142                 ads_destroy(&ads);
2143                 return -1;
2144         }
2145
2146         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2147
2148         /* dump the results */
2149         ads_dump(ads, res);
2150
2151         ads_msgfree(ads, res);
2152         ads_destroy(&ads);
2153
2154         return 0;
2155 }
2156
2157 /*
2158   help for net ads sid search
2159 */
2160 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2161 {
2162         d_printf(_(
2163                 "\nnet ads sid <sid> <attributes...>\n"
2164                 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2165                 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2166                 "to show in the results\n\n"
2167                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2168                 ));
2169         net_common_flags_usage(c, argc, argv);
2170         return -1;
2171 }
2172
2173
2174 /*
2175   general ADS search function. Useful in diagnosing problems in ADS
2176 */
2177 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2178 {
2179         ADS_STRUCT *ads;
2180         ADS_STATUS rc;
2181         const char *sid_string;
2182         const char **attrs;
2183         LDAPMessage *res = NULL;
2184         DOM_SID sid;
2185
2186         if (argc < 1 || c->display_usage) {
2187                 return net_ads_sid_usage(c, argc, argv);
2188         }
2189
2190         if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2191                 return -1;
2192         }
2193
2194         sid_string = argv[0];
2195         attrs = (argv + 1);
2196
2197         if (!string_to_sid(&sid, sid_string)) {
2198                 d_fprintf(stderr, _("could not convert sid\n"));
2199                 ads_destroy(&ads);
2200                 return -1;
2201         }
2202
2203         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2204         if (!ADS_ERR_OK(rc)) {
2205                 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2206                 ads_destroy(&ads);
2207                 return -1;
2208         }
2209
2210         d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2211
2212         /* dump the results */
2213         ads_dump(ads, res);
2214
2215         ads_msgfree(ads, res);
2216         ads_destroy(&ads);
2217
2218         return 0;
2219 }
2220
2221 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2222 {
2223         int ret;
2224         ADS_STRUCT *ads;
2225
2226         if (c->display_usage) {
2227                 d_printf(  "%s\n"
2228                            "net ads keytab flush\n"
2229                            "    %s\n",
2230                          _("Usage:"),
2231                          _("Delete the whole keytab"));
2232                 return 0;
2233         }
2234
2235         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2236                 return -1;
2237         }
2238         ret = ads_keytab_flush(ads);
2239         ads_destroy(&ads);
2240         return ret;
2241 }
2242
2243 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2244 {
2245         int i;
2246         int ret = 0;
2247         ADS_STRUCT *ads;
2248
2249         if (c->display_usage) {
2250                 d_printf("%s\n%s",
2251                          _("Usage:"),
2252                          _("net ads keytab add <principal> [principal ...]\n"
2253                            "  Add principals to local keytab\n"
2254                            "    principal\tKerberos principal to add to "
2255                            "keytab\n"));
2256                 return 0;
2257         }
2258
2259         d_printf(_("Processing principals to add...\n"));
2260         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2261                 return -1;
2262         }
2263         for (i = 0; i < argc; i++) {
2264                 ret |= ads_keytab_add_entry(ads, argv[i]);
2265         }
2266         ads_destroy(&ads);
2267         return ret;
2268 }
2269
2270 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2271 {
2272         ADS_STRUCT *ads;
2273         int ret;
2274
2275         if (c->display_usage) {
2276                 d_printf(  "%s\n"
2277                            "net ads keytab create\n"
2278                            "    %s\n",
2279                          _("Usage:"),
2280                          _("Create new default keytab"));
2281                 return 0;
2282         }
2283
2284         if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2285                 return -1;
2286         }
2287         ret = ads_keytab_create_default(ads);
2288         ads_destroy(&ads);
2289         return ret;
2290 }
2291
2292 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2293 {
2294         const char *keytab = NULL;
2295
2296         if (c->display_usage) {
2297                 d_printf("%s\n%s",
2298                          _("Usage:"),
2299                          _("net ads keytab list [keytab]\n"
2300                            "  List a local keytab\n"
2301                            "    keytab\tKeytab to list\n"));
2302                 return 0;
2303         }
2304
2305         if (argc >= 1) {
2306                 keytab = argv[0];
2307         }
2308
2309         return ads_keytab_list(keytab);
2310 }
2311
2312
2313 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2314 {
2315         struct functable func[] = {
2316                 {
2317                         "add",
2318                         net_ads_keytab_add,
2319                         NET_TRANSPORT_ADS,
2320                         N_("Add a service principal"),
2321                         N_("net ads keytab add\n"
2322                            "    Add a service principal")
2323                 },
2324                 {
2325                         "create",
2326                         net_ads_keytab_create,
2327                         NET_TRANSPORT_ADS,
2328                         N_("Create a fresh keytab"),
2329                         N_("net ads keytab create\n"
2330                            "    Create a fresh keytab")
2331                 },
2332                 {
2333                         "flush",
2334                         net_ads_keytab_flush,
2335                         NET_TRANSPORT_ADS,
2336                         N_("Remove all keytab entries"),
2337                         N_("net ads keytab flush\n"
2338                            "    Remove all keytab entries")
2339                 },
2340                 {
2341                         "list",
2342                         net_ads_keytab_list,
2343                         NET_TRANSPORT_ADS,
2344                         N_("List a keytab"),
2345                         N_("net ads keytab list\n"
2346                            "    List a keytab")
2347                 },
2348                 {NULL, NULL, 0, NULL, NULL}
2349         };
2350
2351         if (!USE_KERBEROS_KEYTAB) {
2352                 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2353                     "keytab method to use keytab functions.\n"));
2354         }
2355
2356         return net_run_function(c, argc, argv, "net ads keytab", func);
2357 }
2358
2359 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2360 {
2361         int ret = -1;
2362
2363         if (c->display_usage) {
2364                 d_printf(  "%s\n"
2365                            "net ads kerberos renew\n"
2366                            "    %s\n",
2367                          _("Usage:"),
2368                          _("Renew TGT from existing credential cache"));
2369                 return 0;
2370         }
2371
2372         ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2373         if (ret) {
2374                 d_printf(_("failed to renew kerberos ticket: %s\n"),
2375                         error_message(ret));
2376         }
2377         return ret;
2378 }
2379
2380 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2381 {
2382         struct PAC_DATA *pac = NULL;
2383         struct PAC_LOGON_INFO *info = NULL;
2384         TALLOC_CTX *mem_ctx = NULL;
2385         NTSTATUS status;
2386         int ret = -1;
2387         const char *impersonate_princ_s = NULL;
2388
2389         if (c->display_usage) {
2390                 d_printf(  "%s\n"
2391                            "net ads kerberos pac\n"
2392                            "    %s\n",
2393                          _("Usage:"),
2394                          _("Dump the Kerberos PAC"));
2395                 return 0;
2396         }
2397
2398         mem_ctx = talloc_init("net_ads_kerberos_pac");
2399         if (!mem_ctx) {
2400                 goto out;
2401         }
2402
2403         if (argc > 0) {
2404                 impersonate_princ_s = argv[0];
2405         }
2406
2407         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2408
2409         status = kerberos_return_pac(mem_ctx,
2410                                      c->opt_user_name,
2411                                      c->opt_password,
2412                                      0,
2413                                      NULL,
2414                                      NULL,
2415                                      NULL,
2416                                      true,
2417                                      true,
2418                                      2592000, /* one month */
2419                                      impersonate_princ_s,
2420                                      &pac);
2421         if (!NT_STATUS_IS_OK(status)) {
2422                 d_printf(_("failed to query kerberos PAC: %s\n"),
2423                         nt_errstr(status));
2424                 goto out;
2425         }
2426
2427         info = get_logon_info_from_pac(pac);
2428         if (info) {
2429                 const char *s;
2430                 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2431                 d_printf(_("The Pac: %s\n"), s);
2432         }
2433
2434         ret = 0;
2435  out:
2436         TALLOC_FREE(mem_ctx);
2437         return ret;
2438 }
2439
2440 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2441 {
2442         TALLOC_CTX *mem_ctx = NULL;
2443         int ret = -1;
2444         NTSTATUS status;
2445
2446         if (c->display_usage) {
2447                 d_printf(  "%s\n"
2448                            "net ads kerberos kinit\n"
2449                            "    %s\n",
2450                          _("Usage:"),
2451                          _("Get Ticket Granting Ticket (TGT) for the user"));
2452                 return 0;
2453         }
2454
2455         mem_ctx = talloc_init("net_ads_kerberos_kinit");
2456         if (!mem_ctx) {
2457                 goto out;
2458         }
2459
2460         c->opt_password = net_prompt_pass(c, c->opt_user_name);
2461
2462         ret = kerberos_kinit_password_ext(c->opt_user_name,
2463                                           c->opt_password,
2464                                           0,
2465                                           NULL,
2466                                           NULL,
2467                                           NULL,
2468                                           true,
2469                                           true,
2470                                           2592000, /* one month */
2471                                           &status);
2472         if (ret) {
2473                 d_printf(_("failed to kinit password: %s\n"),
2474                         nt_errstr(status));
2475         }
2476  out:
2477         return ret;
2478 }
2479
2480 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2481 {
2482         struct functable func[] = {
2483                 {
2484                         "kinit",
2485                         net_ads_kerberos_kinit,
2486                         NET_TRANSPORT_ADS,
2487                         N_("Retrieve Ticket Granting Ticket (TGT)"),
2488                         N_("net ads kerberos kinit\n"
2489                            "    Receive Ticket Granting Ticket (TGT)")
2490                 },
2491                 {
2492                         "renew",
2493                         net_ads_kerberos_renew,
2494                         NET_TRANSPORT_ADS,
2495                         N_("Renew Ticket Granting Ticket from credential cache"),
2496                         N_("net ads kerberos renew\n"
2497                            "    Renew Ticket Granting Ticket (TGT) from "
2498                            "credential cache")
2499                 },
2500                 {
2501                         "pac",
2502                         net_ads_kerberos_pac,
2503                         NET_TRANSPORT_ADS,
2504                         N_("Dump Kerberos PAC"),
2505                         N_("net ads kerberos pac\n"
2506                            "    Dump Kerberos PAC")
2507                 },
2508                 {NULL, NULL, 0, NULL, NULL}
2509         };
2510
2511         return net_run_function(c, argc, argv, "net ads kerberos", func);
2512 }
2513
2514 int net_ads(struct net_context *c, int argc, const char **argv)
2515 {
2516         struct functable func[] = {
2517                 {
2518                         "info",
2519                         net_ads_info,
2520                         NET_TRANSPORT_ADS,
2521                         N_("Display details on remote ADS server"),
2522                         N_("net ads info\n"
2523                            "    Display details on remote ADS server")
2524                 },
2525                 {
2526                         "join",
2527                         net_ads_join,
2528                         NET_TRANSPORT_ADS,
2529                         N_("Join the local machine to ADS realm"),
2530                         N_("net ads join\n"
2531                            "    Join the local machine to ADS realm")
2532                 },
2533                 {
2534                         "testjoin",
2535                         net_ads_testjoin,
2536                         NET_TRANSPORT_ADS,
2537                         N_("Validate machine account"),
2538                         N_("net ads testjoin\n"
2539                            "    Validate machine account")
2540                 },
2541                 {
2542                         "leave",
2543                         net_ads_leave,
2544                         NET_TRANSPORT_ADS,
2545                         N_("Remove the local machine from ADS"),
2546                         N_("net ads leave\n"
2547                            "    Remove the local machine from ADS")
2548                 },
2549                 {
2550                         "status",
2551                         net_ads_status,
2552                         NET_TRANSPORT_ADS,
2553                         N_("Display machine account details"),
2554                         N_("net ads status\n"
2555                            "    Display machine account details")
2556                 },
2557                 {
2558                         "user",
2559                         net_ads_user,
2560                         NET_TRANSPORT_ADS,
2561                         N_("List/modify users"),
2562                         N_("net ads user\n"
2563                            "    List/modify users")
2564                 },
2565                 {
2566                         "group",
2567                         net_ads_group,
2568                         NET_TRANSPORT_ADS,
2569                         N_("List/modify groups"),
2570                         N_("net ads group\n"
2571                            "    List/modify groups")
2572                 },
2573                 {
2574                         "dns",
2575                         net_ads_dns,
2576                         NET_TRANSPORT_ADS,
2577                         N_("Issue dynamic DNS update"),
2578                         N_("net ads dns\n"
2579                            "    Issue dynamic DNS update")
2580                 },
2581                 {
2582                         "password",
2583                         net_ads_password,
2584                         NET_TRANSPORT_ADS,
2585                         N_("Change user passwords"),
2586                         N_("net ads password\n"
2587                            "    Change user passwords")
2588                 },
2589                 {
2590                         "changetrustpw",
2591                         net_ads_changetrustpw,
2592                         NET_TRANSPORT_ADS,
2593                         N_("Change trust account password"),
2594                         N_("net ads changetrustpw\n"
2595                            "    Change trust account password")
2596                 },
2597                 {
2598                         "printer",
2599                         net_ads_printer,
2600                         NET_TRANSPORT_ADS,
2601                         N_("List/modify printer entries"),
2602                         N_("net ads printer\n"
2603                            "    List/modify printer entries")
2604                 },
2605                 {
2606                         "search",
2607                         net_ads_search,
2608                         NET_TRANSPORT_ADS,
2609                         N_("Issue LDAP search using filter"),
2610                         N_("net ads search\n"
2611                            "    Issue LDAP search using filter")
2612                 },
2613                 {
2614                         "dn",
2615                         net_ads_dn,
2616                         NET_TRANSPORT_ADS,
2617                         N_("Issue LDAP search by DN"),
2618                         N_("net ads dn\n"
2619                            "    Issue LDAP search by DN")
2620                 },
2621                 {
2622                         "sid",
2623                         net_ads_sid,
2624                         NET_TRANSPORT_ADS,
2625                         N_("Issue LDAP search by SID"),
2626                         N_("net ads sid\n"
2627                            "    Issue LDAP search by SID")
2628                 },
2629                 {
2630                         "workgroup",
2631                         net_ads_workgroup,
2632                         NET_TRANSPORT_ADS,
2633                         N_("Display workgroup name"),
2634                         N_("net ads workgroup\n"
2635                            "    Display the workgroup name")
2636                 },
2637                 {
2638                         "lookup",
2639                         net_ads_lookup,
2640                         NET_TRANSPORT_ADS,
2641                         N_("Perfom CLDAP query on DC"),
2642                         N_("net ads lookup\n"
2643                            "    Find the ADS DC using CLDAP lookups")
2644                 },
2645                 {
2646                         "keytab",
2647                         net_ads_keytab,
2648                         NET_TRANSPORT_ADS,
2649                         N_("Manage local keytab file"),
2650                         N_("net ads keytab\n"
2651                            "    Manage local keytab file")
2652                 },
2653                 {
2654                         "gpo",
2655                         net_ads_gpo,
2656                         NET_TRANSPORT_ADS,
2657                         N_("Manage group policy objects"),
2658                         N_("net ads gpo\n"
2659                            "    Manage group policy objects")
2660                 },
2661                 {
2662                         "kerberos",
2663                         net_ads_kerberos,
2664                         NET_TRANSPORT_ADS,
2665                         N_("Manage kerberos keytab"),
2666                         N_("net ads kerberos\n"
2667                            "    Manage kerberos keytab")
2668                 },
2669                 {NULL, NULL, 0, NULL, NULL}
2670         };
2671
2672         return net_run_function(c, argc, argv, "net ads", func);
2673 }
2674
2675 #else
2676
2677 static int net_ads_noads(void)
2678 {
2679         d_fprintf(stderr, _("ADS support not compiled in\n"));
2680         return -1;
2681 }
2682
2683 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2684 {
2685         return net_ads_noads();
2686 }
2687
2688 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2689 {
2690         return net_ads_noads();
2691 }
2692
2693 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2694 {
2695         return net_ads_noads();
2696 }
2697
2698 int net_ads_join(struct net_context *c, int argc, const char **argv)
2699 {
2700         return net_ads_noads();
2701 }
2702
2703 int net_ads_user(struct net_context *c, int argc, const char **argv)
2704 {
2705         return net_ads_noads();
2706 }
2707
2708 int net_ads_group(struct net_context *c, int argc, const char **argv)
2709 {
2710         return net_ads_noads();
2711 }
2712
2713 /* this one shouldn't display a message */
2714 int net_ads_check(struct net_context *c)
2715 {
2716         return -1;
2717 }
2718
2719 int net_ads_check_our_domain(struct net_context *c)
2720 {
2721         return -1;
2722 }
2723
2724 int net_ads(struct net_context *c, int argc, const char **argv)
2725 {
2726         return net_ads_noads();
2727 }
2728
2729 #endif  /* WITH_ADS */