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