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