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