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