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

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

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