source: vendor/3.6.0/source3/utils/net_ads.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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