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