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

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

Update 3.2 to 3.2.14 (final)

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