source: branches/samba-3.3.x/source/utils/net_ads.c

Last change on this file was 309, checked in by Herwig Bauernfeind, 16 years ago

Update 3.3 to 3.3.7

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