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