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