2 Samba Unix/Linux SMB client library
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)
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.
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.
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/>.
24 #include "utils/net.h"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "nsswitch/libwbclient/wbclient.h"
30 /* when we do not have sufficient input parameters to contact a remote domain
31 * we always fall back to our own realm - Guenther*/
33 static const char *assume_own_realm(struct net_context
*c
)
35 if (!c
->opt_host
&& strequal(lp_workgroup(), c
->opt_target_workgroup
)) {
43 do a cldap netlogon query
45 static int net_ads_cldap_netlogon(struct net_context
*c
, ADS_STRUCT
*ads
)
47 char addr
[INET6_ADDRSTRLEN
];
48 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
50 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
51 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
52 d_fprintf(stderr
, _("CLDAP query failed!\n"));
56 d_printf(_("Information for Domain Controller: %s\n\n"),
59 d_printf(_("Response Type: "));
60 switch (reply
.command
) {
61 case LOGON_SAM_LOGON_USER_UNKNOWN_EX
:
62 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
64 case LOGON_SAM_LOGON_RESPONSE_EX
:
65 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
68 d_printf("0x%x\n", reply
.command
);
72 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply
.domain_uuid
));
76 "\tIs a GC of the forest: %s\n"
77 "\tIs an LDAP server: %s\n"
79 "\tIs running a KDC: %s\n"
80 "\tIs running time services: %s\n"
81 "\tIs the closest DC: %s\n"
83 "\tHas a hardware clock: %s\n"
84 "\tIs a non-domain NC serviced by LDAP server: %s\n"
85 "\tIs NT6 DC that has some secrets: %s\n"
86 "\tIs NT6 DC that has all secrets: %s\n"),
87 (reply
.server_type
& NBT_SERVER_PDC
) ? _("yes") : _("no"),
88 (reply
.server_type
& NBT_SERVER_GC
) ? _("yes") : _("no"),
89 (reply
.server_type
& NBT_SERVER_LDAP
) ? _("yes") : _("no"),
90 (reply
.server_type
& NBT_SERVER_DS
) ? _("yes") : _("no"),
91 (reply
.server_type
& NBT_SERVER_KDC
) ? _("yes") : _("no"),
92 (reply
.server_type
& NBT_SERVER_TIMESERV
) ? _("yes") : _("no"),
93 (reply
.server_type
& NBT_SERVER_CLOSEST
) ? _("yes") : _("no"),
94 (reply
.server_type
& NBT_SERVER_WRITABLE
) ? _("yes") : _("no"),
95 (reply
.server_type
& NBT_SERVER_GOOD_TIMESERV
) ? _("yes") : _("no"),
96 (reply
.server_type
& NBT_SERVER_NDNC
) ? _("yes") : _("no"),
97 (reply
.server_type
& NBT_SERVER_SELECT_SECRET_DOMAIN_6
) ? _("yes") : _("no"),
98 (reply
.server_type
& NBT_SERVER_FULL_SECRET_DOMAIN_6
) ? _("yes") : _("no"));
101 printf(_("Forest:\t\t\t%s\n"), reply
.forest
);
102 printf(_("Domain:\t\t\t%s\n"), reply
.dns_domain
);
103 printf(_("Domain Controller:\t%s\n"), reply
.pdc_dns_name
);
105 printf(_("Pre-Win2k Domain:\t%s\n"), reply
.domain
);
106 printf(_("Pre-Win2k Hostname:\t%s\n"), reply
.pdc_name
);
108 if (*reply
.user_name
) printf(_("User name:\t%s\n"), reply
.user_name
);
110 printf(_("Server Site Name :\t\t%s\n"), reply
.server_site
);
111 printf(_("Client Site Name :\t\t%s\n"), reply
.client_site
);
113 d_printf(_("NT Version: %d\n"), reply
.nt_version
);
114 d_printf(_("LMNT Token: %.2x\n"), reply
.lmnt_token
);
115 d_printf(_("LM20 Token: %.2x\n"), reply
.lm20_token
);
121 this implements the CLDAP based netlogon lookup requests
122 for finding the domain controller of a ADS domain
124 static int net_ads_lookup(struct net_context
*c
, int argc
, const char **argv
)
129 if (c
->display_usage
) {
130 d_printf(_("Usage:\n"
132 " Find the ADS DC using CLDAP lookup.\n"));
136 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
137 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
142 if (!ads
->config
.realm
) {
143 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
144 ads
->ldap
.port
= 389;
147 ret
= net_ads_cldap_netlogon(c
, ads
);
154 static int net_ads_info(struct net_context
*c
, int argc
, const char **argv
)
157 char addr
[INET6_ADDRSTRLEN
];
159 if (c
->display_usage
) {
160 d_printf(_("Usage:\n"
162 " Display information about an Active Directory "
167 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
168 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
172 if (!ads
|| !ads
->config
.realm
) {
173 d_fprintf(stderr
, _("Didn't find the ldap server!\n"));
178 /* Try to set the server's current time since we didn't do a full
179 TCP LDAP session initially */
181 if ( !ADS_ERR_OK(ads_current_time( ads
)) ) {
182 d_fprintf( stderr
, _("Failed to get server's current time!\n"));
185 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
187 d_printf(_("LDAP server: %s\n"), addr
);
188 d_printf(_("LDAP server name: %s\n"), ads
->config
.ldap_server_name
);
189 d_printf(_("Realm: %s\n"), ads
->config
.realm
);
190 d_printf(_("Bind Path: %s\n"), ads
->config
.bind_path
);
191 d_printf(_("LDAP port: %d\n"), ads
->ldap
.port
);
192 d_printf(_("Server time: %s\n"),
193 http_timestring(talloc_tos(), ads
->config
.current_time
));
195 d_printf(_("KDC server: %s\n"), ads
->auth
.kdc_server
);
196 d_printf(_("Server time offset: %d\n"), ads
->auth
.time_offset
);
202 static void use_in_memory_ccache(void) {
203 /* Use in-memory credentials cache so we do not interfere with
204 * existing credentials */
205 setenv(KRB5_ENV_CCNAME
, "MEMORY:net_ads", 1);
208 static ADS_STATUS
ads_startup_int(struct net_context
*c
, bool only_own_domain
,
209 uint32 auth_flags
, ADS_STRUCT
**ads_ret
)
211 ADS_STRUCT
*ads
= NULL
;
213 bool need_password
= false;
214 bool second_time
= false;
216 const char *realm
= NULL
;
217 bool tried_closest_dc
= false;
219 /* lp_realm() should be handled by a command line param,
220 However, the join requires that realm be set in smb.conf
221 and compares our realm with the remote server's so this is
222 ok until someone needs more flexibility */
227 if (only_own_domain
) {
230 realm
= assume_own_realm(c
);
233 ads
= ads_init(realm
, c
->opt_target_workgroup
, c
->opt_host
);
235 if (!c
->opt_user_name
) {
236 c
->opt_user_name
= "administrator";
239 if (c
->opt_user_specified
) {
240 need_password
= true;
244 if (!c
->opt_password
&& need_password
&& !c
->opt_machine_pass
) {
245 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
246 if (!c
->opt_password
) {
248 return ADS_ERROR(LDAP_NO_MEMORY
);
252 if (c
->opt_password
) {
253 use_in_memory_ccache();
254 SAFE_FREE(ads
->auth
.password
);
255 ads
->auth
.password
= smb_xstrdup(c
->opt_password
);
258 ads
->auth
.flags
|= auth_flags
;
259 SAFE_FREE(ads
->auth
.user_name
);
260 ads
->auth
.user_name
= smb_xstrdup(c
->opt_user_name
);
263 * If the username is of the form "name@realm",
264 * extract the realm and convert to upper case.
265 * This is only used to establish the connection.
267 if ((cp
= strchr_m(ads
->auth
.user_name
, '@'))!=0) {
269 SAFE_FREE(ads
->auth
.realm
);
270 ads
->auth
.realm
= smb_xstrdup(cp
);
271 strupper_m(ads
->auth
.realm
);
274 status
= ads_connect(ads
);
276 if (!ADS_ERR_OK(status
)) {
278 if (NT_STATUS_EQUAL(ads_ntstatus(status
),
279 NT_STATUS_NO_LOGON_SERVERS
)) {
280 DEBUG(0,("ads_connect: %s\n", ads_errstr(status
)));
285 if (!need_password
&& !second_time
&& !(auth_flags
& ADS_AUTH_NO_BIND
)) {
286 need_password
= true;
295 /* when contacting our own domain, make sure we use the closest DC.
296 * This is done by reconnecting to ADS because only the first call to
297 * ads_connect will give us our own sitename */
299 if ((only_own_domain
|| !c
->opt_host
) && !tried_closest_dc
) {
301 tried_closest_dc
= true; /* avoid loop */
303 if (!ads_closest_dc(ads
)) {
305 namecache_delete(ads
->server
.realm
, 0x1C);
306 namecache_delete(ads
->server
.workgroup
, 0x1C);
319 ADS_STATUS
ads_startup(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
321 return ads_startup_int(c
, only_own_domain
, 0, ads
);
324 ADS_STATUS
ads_startup_nobind(struct net_context
*c
, bool only_own_domain
, ADS_STRUCT
**ads
)
326 return ads_startup_int(c
, only_own_domain
, ADS_AUTH_NO_BIND
, ads
);
330 Check to see if connection can be made via ads.
331 ads_startup() stores the password in opt_password if it needs to so
332 that rpc or rap can use it without re-prompting.
334 static int net_ads_check_int(const char *realm
, const char *workgroup
, const char *host
)
339 if ( (ads
= ads_init( realm
, workgroup
, host
)) == NULL
) {
343 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
345 status
= ads_connect(ads
);
346 if ( !ADS_ERR_OK(status
) ) {
354 int net_ads_check_our_domain(struct net_context
*c
)
356 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL
);
359 int net_ads_check(struct net_context
*c
)
361 return net_ads_check_int(NULL
, c
->opt_workgroup
, c
->opt_host
);
365 determine the netbios workgroup name for a domain
367 static int net_ads_workgroup(struct net_context
*c
, int argc
, const char **argv
)
370 char addr
[INET6_ADDRSTRLEN
];
371 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply
;
373 if (c
->display_usage
) {
374 d_printf(_("Usage:\n"
375 "net ads workgroup\n"
376 " Print the workgroup name\n"));
380 if (!ADS_ERR_OK(ads_startup_nobind(c
, false, &ads
))) {
381 d_fprintf(stderr
, _("Didn't find the cldap server!\n"));
385 if (!ads
->config
.realm
) {
386 ads
->config
.realm
= CONST_DISCARD(char *, c
->opt_target_workgroup
);
387 ads
->ldap
.port
= 389;
390 print_sockaddr(addr
, sizeof(addr
), &ads
->ldap
.ss
);
391 if ( !ads_cldap_netlogon_5(talloc_tos(), addr
, ads
->server
.realm
, &reply
) ) {
392 d_fprintf(stderr
, _("CLDAP query failed!\n"));
397 d_printf(_("Workgroup: %s\n"), reply
.domain
);
406 static bool usergrp_display(ADS_STRUCT
*ads
, char *field
, void **values
, void *data_area
)
408 char **disp_fields
= (char **) data_area
;
410 if (!field
) { /* must be end of record */
411 if (disp_fields
[0]) {
412 if (!strchr_m(disp_fields
[0], '$')) {
414 d_printf("%-21.21s %s\n",
415 disp_fields
[0], disp_fields
[1]);
417 d_printf("%s\n", disp_fields
[0]);
420 SAFE_FREE(disp_fields
[0]);
421 SAFE_FREE(disp_fields
[1]);
424 if (!values
) /* must be new field, indicate string field */
426 if (StrCaseCmp(field
, "sAMAccountName") == 0) {
427 disp_fields
[0] = SMB_STRDUP((char *) values
[0]);
429 if (StrCaseCmp(field
, "description") == 0)
430 disp_fields
[1] = SMB_STRDUP((char *) values
[0]);
434 static int net_ads_user_usage(struct net_context
*c
, int argc
, const char **argv
)
436 return net_user_usage(c
, argc
, argv
);
439 static int ads_user_add(struct net_context
*c
, int argc
, const char **argv
)
444 LDAPMessage
*res
=NULL
;
448 if (argc
< 1 || c
->display_usage
)
449 return net_ads_user_usage(c
, argc
, argv
);
451 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
455 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
457 if (!ADS_ERR_OK(status
)) {
458 d_fprintf(stderr
, _("ads_user_add: %s\n"), ads_errstr(status
));
462 if (ads_count_replies(ads
, res
)) {
463 d_fprintf(stderr
, _("ads_user_add: User %s already exists\n"),
468 if (c
->opt_container
) {
469 ou_str
= SMB_STRDUP(c
->opt_container
);
471 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
474 status
= ads_add_user_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
476 if (!ADS_ERR_OK(status
)) {
477 d_fprintf(stderr
, _("Could not add user %s: %s\n"), argv
[0],
482 /* if no password is to be set, we're done */
484 d_printf(_("User %s added\n"), argv
[0]);
489 /* try setting the password */
490 if (asprintf(&upn
, "%s@%s", argv
[0], ads
->config
.realm
) == -1) {
493 status
= ads_krb5_set_password(ads
->auth
.kdc_server
, upn
, argv
[1],
494 ads
->auth
.time_offset
);
496 if (ADS_ERR_OK(status
)) {
497 d_printf(_("User %s added\n"), argv
[0]);
502 /* password didn't set, delete account */
503 d_fprintf(stderr
, _("Could not add user %s. "
504 "Error setting password %s\n"),
505 argv
[0], ads_errstr(status
));
506 ads_msgfree(ads
, res
);
507 status
=ads_find_user_acct(ads
, &res
, argv
[0]);
508 if (ADS_ERR_OK(status
)) {
509 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
510 ads_del_dn(ads
, userdn
);
516 ads_msgfree(ads
, res
);
522 static int ads_user_info(struct net_context
*c
, int argc
, const char **argv
)
524 ADS_STRUCT
*ads
= NULL
;
526 LDAPMessage
*res
= NULL
;
530 const char *attrs
[] = {"memberOf", "primaryGroupID", NULL
};
531 char *searchstring
=NULL
;
535 DOM_SID primary_group_sid
;
537 enum SID_NAME_USE type
;
539 if (argc
< 1 || c
->display_usage
) {
540 return net_ads_user_usage(c
, argc
, argv
);
543 frame
= talloc_new(talloc_tos());
548 escaped_user
= escape_ldap_string(frame
, argv
[0]);
551 _("ads_user_info: failed to escape user %s\n"),
556 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
561 if (asprintf(&searchstring
, "(sAMAccountName=%s)", escaped_user
) == -1) {
565 rc
= ads_search(ads
, &res
, searchstring
, attrs
);
566 SAFE_FREE(searchstring
);
568 if (!ADS_ERR_OK(rc
)) {
569 d_fprintf(stderr
, _("ads_search: %s\n"), ads_errstr(rc
));
574 if (!ads_pull_uint32(ads
, res
, "primaryGroupID", &group_rid
)) {
575 d_fprintf(stderr
, _("ads_pull_uint32 failed\n"));
580 rc
= ads_domain_sid(ads
, &primary_group_sid
);
581 if (!ADS_ERR_OK(rc
)) {
582 d_fprintf(stderr
, _("ads_domain_sid: %s\n"), ads_errstr(rc
));
587 sid_append_rid(&primary_group_sid
, group_rid
);
589 wbc_status
= wbcLookupSid((struct wbcDomainSid
*)&primary_group_sid
,
590 NULL
, /* don't look up domain */
592 (enum wbcSidType
*) &type
);
593 if (!WBC_ERROR_IS_OK(wbc_status
)) {
594 d_fprintf(stderr
, "wbcLookupSid: %s\n",
595 wbcErrorString(wbc_status
));
600 d_printf("%s\n", primary_group
);
602 wbcFreeMemory(primary_group
);
604 grouplist
= ldap_get_values((LDAP
*)ads
->ldap
.ld
,
605 (LDAPMessage
*)res
, "memberOf");
610 for (i
=0;grouplist
[i
];i
++) {
611 groupname
= ldap_explode_dn(grouplist
[i
], 1);
612 d_printf("%s\n", groupname
[0]);
613 ldap_value_free(groupname
);
615 ldap_value_free(grouplist
);
619 if (res
) ads_msgfree(ads
, res
);
620 if (ads
) ads_destroy(&ads
);
625 static int ads_user_delete(struct net_context
*c
, int argc
, const char **argv
)
629 LDAPMessage
*res
= NULL
;
633 return net_ads_user_usage(c
, argc
, argv
);
636 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
640 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
641 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
642 d_printf(_("User %s does not exist.\n"), argv
[0]);
643 ads_msgfree(ads
, res
);
647 userdn
= ads_get_dn(ads
, talloc_tos(), res
);
648 ads_msgfree(ads
, res
);
649 rc
= ads_del_dn(ads
, userdn
);
651 if (ADS_ERR_OK(rc
)) {
652 d_printf(_("User %s deleted\n"), argv
[0]);
656 d_fprintf(stderr
, _("Error deleting user %s: %s\n"), argv
[0],
662 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
664 struct functable func
[] = {
669 N_("Add an AD user"),
670 N_("net ads user add\n"
677 N_("Display information about an AD user"),
678 N_("net ads user info\n"
679 " Display information about an AD user")
685 N_("Delete an AD user"),
686 N_("net ads user delete\n"
687 " Delete an AD user")
689 {NULL
, NULL
, 0, NULL
, NULL
}
693 const char *shortattrs
[] = {"sAMAccountName", NULL
};
694 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
695 char *disp_fields
[2] = {NULL
, NULL
};
698 if (c
->display_usage
) {
699 d_printf(_("Usage:\n"
701 " List AD users\n"));
702 net_display_usage_from_functable(func
);
706 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
710 if (c
->opt_long_list_entries
)
711 d_printf(_("\nUser name Comment"
712 "\n-----------------------------\n"));
714 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
716 "(objectCategory=user)",
717 c
->opt_long_list_entries
? longattrs
:
718 shortattrs
, usergrp_display
,
721 return ADS_ERR_OK(rc
) ? 0 : -1;
724 return net_run_function(c
, argc
, argv
, "net ads user", func
);
727 static int net_ads_group_usage(struct net_context
*c
, int argc
, const char **argv
)
729 return net_group_usage(c
, argc
, argv
);
732 static int ads_group_add(struct net_context
*c
, int argc
, const char **argv
)
736 LDAPMessage
*res
=NULL
;
740 if (argc
< 1 || c
->display_usage
) {
741 return net_ads_group_usage(c
, argc
, argv
);
744 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
748 status
= ads_find_user_acct(ads
, &res
, argv
[0]);
750 if (!ADS_ERR_OK(status
)) {
751 d_fprintf(stderr
, _("ads_group_add: %s\n"), ads_errstr(status
));
755 if (ads_count_replies(ads
, res
)) {
756 d_fprintf(stderr
, _("ads_group_add: Group %s already exists\n"), argv
[0]);
760 if (c
->opt_container
) {
761 ou_str
= SMB_STRDUP(c
->opt_container
);
763 ou_str
= ads_default_ou_string(ads
, WELL_KNOWN_GUID_USERS
);
766 status
= ads_add_group_acct(ads
, argv
[0], ou_str
, c
->opt_comment
);
768 if (ADS_ERR_OK(status
)) {
769 d_printf(_("Group %s added\n"), argv
[0]);
772 d_fprintf(stderr
, _("Could not add group %s: %s\n"), argv
[0],
778 ads_msgfree(ads
, res
);
784 static int ads_group_delete(struct net_context
*c
, int argc
, const char **argv
)
788 LDAPMessage
*res
= NULL
;
791 if (argc
< 1 || c
->display_usage
) {
792 return net_ads_group_usage(c
, argc
, argv
);
795 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
799 rc
= ads_find_user_acct(ads
, &res
, argv
[0]);
800 if (!ADS_ERR_OK(rc
) || ads_count_replies(ads
, res
) != 1) {
801 d_printf(_("Group %s does not exist.\n"), argv
[0]);
802 ads_msgfree(ads
, res
);
806 groupdn
= ads_get_dn(ads
, talloc_tos(), res
);
807 ads_msgfree(ads
, res
);
808 rc
= ads_del_dn(ads
, groupdn
);
809 TALLOC_FREE(groupdn
);
810 if (ADS_ERR_OK(rc
)) {
811 d_printf(_("Group %s deleted\n"), argv
[0]);
815 d_fprintf(stderr
, _("Error deleting group %s: %s\n"), argv
[0],
821 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
823 struct functable func
[] = {
828 N_("Add an AD group"),
829 N_("net ads group add\n"
836 N_("Delete an AD group"),
837 N_("net ads group delete\n"
838 " Delete an AD group")
840 {NULL
, NULL
, 0, NULL
, NULL
}
844 const char *shortattrs
[] = {"sAMAccountName", NULL
};
845 const char *longattrs
[] = {"sAMAccountName", "description", NULL
};
846 char *disp_fields
[2] = {NULL
, NULL
};
849 if (c
->display_usage
) {
850 d_printf(_("Usage:\n"
852 " List AD groups\n"));
853 net_display_usage_from_functable(func
);
857 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
861 if (c
->opt_long_list_entries
)
862 d_printf(_("\nGroup name Comment"
863 "\n-----------------------------\n"));
864 rc
= ads_do_search_all_fn(ads
, ads
->config
.bind_path
,
866 "(objectCategory=group)",
867 c
->opt_long_list_entries
? longattrs
:
868 shortattrs
, usergrp_display
,
872 return ADS_ERR_OK(rc
) ? 0 : -1;
874 return net_run_function(c
, argc
, argv
, "net ads group", func
);
877 static int net_ads_status(struct net_context
*c
, int argc
, const char **argv
)
883 if (c
->display_usage
) {
884 d_printf(_("Usage:\n"
886 " Display machine account details\n"));
890 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
894 rc
= ads_find_machine_acct(ads
, &res
, global_myname());
895 if (!ADS_ERR_OK(rc
)) {
896 d_fprintf(stderr
, _("ads_find_machine_acct: %s\n"), ads_errstr(rc
));
901 if (ads_count_replies(ads
, res
) == 0) {
902 d_fprintf(stderr
, _("No machine account for '%s' found\n"), global_myname());
912 /*******************************************************************
913 Leave an AD domain. Windows XP disables the machine account.
914 We'll try the same. The old code would do an LDAP delete.
915 That only worked using the machine creds because added the machine
916 with full control to the computer object's ACL.
917 *******************************************************************/
919 static int net_ads_leave(struct net_context
*c
, int argc
, const char **argv
)
922 struct libnet_UnjoinCtx
*r
= NULL
;
925 if (c
->display_usage
) {
926 d_printf(_("Usage:\n"
928 " Leave an AD domain\n"));
933 d_fprintf(stderr
, _("No realm set, are we joined ?\n"));
937 if (!(ctx
= talloc_init("net_ads_leave"))) {
938 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
942 if (!c
->opt_kerberos
) {
943 use_in_memory_ccache();
946 werr
= libnet_init_UnjoinCtx(ctx
, &r
);
947 if (!W_ERROR_IS_OK(werr
)) {
948 d_fprintf(stderr
, _("Could not initialise unjoin context.\n"));
953 r
->in
.use_kerberos
= c
->opt_kerberos
;
954 r
->in
.dc_name
= c
->opt_host
;
955 r
->in
.domain_name
= lp_realm();
956 r
->in
.admin_account
= c
->opt_user_name
;
957 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
958 r
->in
.modify_config
= lp_config_backend_is_registry();
960 /* Try to delete it, but if that fails, disable it. The
961 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
962 r
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
963 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
964 r
->in
.delete_machine_account
= true;
966 werr
= libnet_Unjoin(ctx
, r
);
967 if (!W_ERROR_IS_OK(werr
)) {
968 d_printf(_("Failed to leave domain: %s\n"),
969 r
->out
.error_string
? r
->out
.error_string
:
970 get_friendly_werror_msg(werr
));
974 if (r
->out
.deleted_machine_account
) {
975 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
976 r
->in
.machine_name
, r
->out
.dns_domain_name
);
980 /* We couldn't delete it - see if the disable succeeded. */
981 if (r
->out
.disabled_machine_account
) {
982 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
983 r
->in
.machine_name
, r
->out
.dns_domain_name
);
988 /* Based on what we requseted, we shouldn't get here, but if
989 we did, it means the secrets were removed, and therefore
990 we have left the domain */
991 d_fprintf(stderr
, _("Machine '%s' Left domain '%s'\n"),
992 r
->in
.machine_name
, r
->out
.dns_domain_name
);
998 if (W_ERROR_IS_OK(werr
)) {
1005 static NTSTATUS
net_ads_join_ok(struct net_context
*c
)
1007 ADS_STRUCT
*ads
= NULL
;
1010 if (!secrets_init()) {
1011 DEBUG(1,("Failed to initialise secrets database\n"));
1012 return NT_STATUS_ACCESS_DENIED
;
1015 net_use_krb_machine_account(c
);
1017 status
= ads_startup(c
, true, &ads
);
1018 if (!ADS_ERR_OK(status
)) {
1019 return ads_ntstatus(status
);
1023 return NT_STATUS_OK
;
1027 check that an existing join is OK
1029 int net_ads_testjoin(struct net_context
*c
, int argc
, const char **argv
)
1032 use_in_memory_ccache();
1034 if (c
->display_usage
) {
1035 d_printf(_("Usage:\n"
1036 "net ads testjoin\n"
1037 " Test if the existing join is ok\n"));
1041 /* Display success or failure */
1042 status
= net_ads_join_ok(c
);
1043 if (!NT_STATUS_IS_OK(status
)) {
1044 fprintf(stderr
, _("Join to domain is not valid: %s\n"),
1045 get_friendly_nt_error_msg(status
));
1049 printf(_("Join is OK\n"));
1053 /*******************************************************************
1054 Simple configu checks before beginning the join
1055 ********************************************************************/
1057 static WERROR
check_ads_config( void )
1059 if (lp_server_role() != ROLE_DOMAIN_MEMBER
) {
1060 d_printf(_("Host is not configured as a member server.\n"));
1061 return WERR_INVALID_DOMAIN_ROLE
;
1064 if (strlen(global_myname()) > 15) {
1065 d_printf(_("Our netbios name can be at most 15 chars long, "
1066 "\"%s\" is %u chars long\n"), global_myname(),
1067 (unsigned int)strlen(global_myname()));
1068 return WERR_INVALID_COMPUTERNAME
;
1071 if ( lp_security() == SEC_ADS
&& !*lp_realm()) {
1072 d_fprintf(stderr
, _("realm must be set in in %s for ADS "
1073 "join to succeed.\n"), get_dyn_CONFIGFILE());
1074 return WERR_INVALID_PARAM
;
1080 /*******************************************************************
1081 Send a DNS update request
1082 *******************************************************************/
1084 #if defined(WITH_DNS_UPDATES)
1086 DNS_ERROR
DoDNSUpdate(char *pszServerName
,
1087 const char *pszDomainName
, const char *pszHostName
,
1088 const struct sockaddr_storage
*sslist
,
1091 static NTSTATUS
net_update_dns_internal(TALLOC_CTX
*ctx
, ADS_STRUCT
*ads
,
1092 const char *machine_name
,
1093 const struct sockaddr_storage
*addrs
,
1096 struct dns_rr_ns
*nameservers
= NULL
;
1098 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1101 const char *dnsdomain
= NULL
;
1102 char *root_domain
= NULL
;
1104 if ( (dnsdomain
= strchr_m( machine_name
, '.')) == NULL
) {
1105 d_printf(_("No DNS domain configured for %s. "
1106 "Unable to perform DNS Update.\n"), machine_name
);
1107 status
= NT_STATUS_INVALID_PARAMETER
;
1112 status
= ads_dns_lookup_ns( ctx
, dnsdomain
, &nameservers
, &ns_count
);
1113 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1114 /* Child domains often do not have NS records. Look
1115 for the NS record for the forest root domain
1116 (rootDomainNamingContext in therootDSE) */
1118 const char *rootname_attrs
[] = { "rootDomainNamingContext", NULL
};
1119 LDAPMessage
*msg
= NULL
;
1121 ADS_STATUS ads_status
;
1123 if ( !ads
->ldap
.ld
) {
1124 ads_status
= ads_connect( ads
);
1125 if ( !ADS_ERR_OK(ads_status
) ) {
1126 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1131 ads_status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
,
1132 "(objectclass=*)", rootname_attrs
, &msg
);
1133 if (!ADS_ERR_OK(ads_status
)) {
1137 root_dn
= ads_pull_string(ads
, ctx
, msg
, "rootDomainNamingContext");
1139 ads_msgfree( ads
, msg
);
1143 root_domain
= ads_build_domain( root_dn
);
1146 ads_msgfree( ads
, msg
);
1148 /* try again for NS servers */
1150 status
= ads_dns_lookup_ns( ctx
, root_domain
, &nameservers
, &ns_count
);
1152 if ( !NT_STATUS_IS_OK(status
) || (ns_count
== 0)) {
1153 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1154 "realm\n", ads
->config
.realm
));
1158 dnsdomain
= root_domain
;
1162 /* Now perform the dns update - we'll try non-secure and if we fail,
1163 we'll follow it up with a secure update */
1165 fstrcpy( dns_server
, nameservers
[0].hostname
);
1167 dns_err
= DoDNSUpdate(dns_server
, dnsdomain
, machine_name
, addrs
, num_addrs
);
1168 if (!ERR_DNS_IS_OK(dns_err
)) {
1169 status
= NT_STATUS_UNSUCCESSFUL
;
1174 SAFE_FREE( root_domain
);
1179 static NTSTATUS
net_update_dns(TALLOC_CTX
*mem_ctx
, ADS_STRUCT
*ads
)
1182 struct sockaddr_storage
*iplist
= NULL
;
1183 fstring machine_name
;
1186 name_to_fqdn( machine_name
, global_myname() );
1187 strlower_m( machine_name
);
1189 /* Get our ip address (not the 127.0.0.x address but a real ip
1192 num_addrs
= get_my_ip_address( &iplist
);
1193 if ( num_addrs
<= 0 ) {
1194 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1196 return NT_STATUS_INVALID_PARAMETER
;
1199 status
= net_update_dns_internal(mem_ctx
, ads
, machine_name
,
1201 SAFE_FREE( iplist
);
1207 /*******************************************************************
1208 ********************************************************************/
1210 static int net_ads_join_usage(struct net_context
*c
, int argc
, const char **argv
)
1212 d_printf(_("net ads join [options]\n"
1213 "Valid options:\n"));
1214 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1215 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1216 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1217 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1218 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1219 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1220 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1221 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1222 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1223 " NB: osName and osVer must be specified together for either to take effect.\n"
1224 " Also, the operatingSystemService attribute is also set when along with\n"
1225 " the two other attributes.\n"));
1230 /*******************************************************************
1231 ********************************************************************/
1233 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
1235 TALLOC_CTX
*ctx
= NULL
;
1236 struct libnet_JoinCtx
*r
= NULL
;
1237 const char *domain
= lp_realm();
1238 WERROR werr
= WERR_SETUP_NOT_JOINED
;
1239 bool createupn
= false;
1240 const char *machineupn
= NULL
;
1241 const char *create_in_ou
= NULL
;
1243 const char *os_name
= NULL
;
1244 const char *os_version
= NULL
;
1245 bool modify_config
= lp_config_backend_is_registry();
1247 if (c
->display_usage
)
1248 return net_ads_join_usage(c
, argc
, argv
);
1250 if (!modify_config
) {
1252 werr
= check_ads_config();
1253 if (!W_ERROR_IS_OK(werr
)) {
1254 d_fprintf(stderr
, _("Invalid configuration. Exiting....\n"));
1259 if (!(ctx
= talloc_init("net_ads_join"))) {
1260 d_fprintf(stderr
, _("Could not initialise talloc context.\n"));
1265 if (!c
->opt_kerberos
) {
1266 use_in_memory_ccache();
1269 werr
= libnet_init_JoinCtx(ctx
, &r
);
1270 if (!W_ERROR_IS_OK(werr
)) {
1274 /* process additional command line args */
1276 for ( i
=0; i
<argc
; i
++ ) {
1277 if ( !StrnCaseCmp(argv
[i
], "createupn", strlen("createupn")) ) {
1279 machineupn
= get_string_param(argv
[i
]);
1281 else if ( !StrnCaseCmp(argv
[i
], "createcomputer", strlen("createcomputer")) ) {
1282 if ( (create_in_ou
= get_string_param(argv
[i
])) == NULL
) {
1283 d_fprintf(stderr
, _("Please supply a valid OU path.\n"));
1284 werr
= WERR_INVALID_PARAM
;
1288 else if ( !StrnCaseCmp(argv
[i
], "osName", strlen("osName")) ) {
1289 if ( (os_name
= get_string_param(argv
[i
])) == NULL
) {
1290 d_fprintf(stderr
, _("Please supply a operating system name.\n"));
1291 werr
= WERR_INVALID_PARAM
;
1295 else if ( !StrnCaseCmp(argv
[i
], "osVer", strlen("osVer")) ) {
1296 if ( (os_version
= get_string_param(argv
[i
])) == NULL
) {
1297 d_fprintf(stderr
, _("Please supply a valid operating system version.\n"));
1298 werr
= WERR_INVALID_PARAM
;
1308 d_fprintf(stderr
, _("Please supply a valid domain name\n"));
1309 werr
= WERR_INVALID_PARAM
;
1313 /* Do the domain join here */
1315 r
->in
.domain_name
= domain
;
1316 r
->in
.create_upn
= createupn
;
1317 r
->in
.upn
= machineupn
;
1318 r
->in
.account_ou
= create_in_ou
;
1319 r
->in
.os_name
= os_name
;
1320 r
->in
.os_version
= os_version
;
1321 r
->in
.dc_name
= c
->opt_host
;
1322 r
->in
.admin_account
= c
->opt_user_name
;
1323 r
->in
.admin_password
= net_prompt_pass(c
, c
->opt_user_name
);
1325 r
->in
.use_kerberos
= c
->opt_kerberos
;
1326 r
->in
.modify_config
= modify_config
;
1327 r
->in
.join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1328 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
1329 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
;
1331 werr
= libnet_Join(ctx
, r
);
1332 if (!W_ERROR_IS_OK(werr
)) {
1336 /* Check the short name of the domain */
1338 if (!modify_config
&& !strequal(lp_workgroup(), r
->out
.netbios_domain_name
)) {
1339 d_printf(_("The workgroup in %s does not match the short\n"
1340 "domain name obtained from the server.\n"
1341 "Using the name [%s] from the server.\n"
1342 "You should set \"workgroup = %s\" in %s.\n"),
1343 get_dyn_CONFIGFILE(), r
->out
.netbios_domain_name
,
1344 r
->out
.netbios_domain_name
, get_dyn_CONFIGFILE());
1347 d_printf(_("Using short domain name -- %s\n"), r
->out
.netbios_domain_name
);
1349 if (r
->out
.dns_domain_name
) {
1350 d_printf(_("Joined '%s' to realm '%s'\n"), r
->in
.machine_name
,
1351 r
->out
.dns_domain_name
);
1353 d_printf(_("Joined '%s' to domain '%s'\n"), r
->in
.machine_name
,
1354 r
->out
.netbios_domain_name
);
1357 #if defined(WITH_DNS_UPDATES)
1358 if (r
->out
.domain_is_ad
) {
1359 /* We enter this block with user creds */
1360 ADS_STRUCT
*ads_dns
= NULL
;
1362 if ( (ads_dns
= ads_init( lp_realm(), NULL
, NULL
)) != NULL
) {
1363 /* kinit with the machine password */
1365 use_in_memory_ccache();
1366 if (asprintf( &ads_dns
->auth
.user_name
, "%s$", global_myname()) == -1) {
1369 ads_dns
->auth
.password
= secrets_fetch_machine_password(
1370 r
->out
.netbios_domain_name
, NULL
, NULL
);
1371 ads_dns
->auth
.realm
= SMB_STRDUP( r
->out
.dns_domain_name
);
1372 strupper_m(ads_dns
->auth
.realm
);
1373 ads_kinit_password( ads_dns
);
1376 if ( !ads_dns
|| !NT_STATUS_IS_OK(net_update_dns( ctx
, ads_dns
)) ) {
1377 d_fprintf( stderr
, _("DNS update failed!\n") );
1380 /* exit from this block using machine creds */
1381 ads_destroy(&ads_dns
);
1390 /* issue an overall failure message at the end. */
1391 d_printf(_("Failed to join domain: %s\n"),
1392 r
&& r
->out
.error_string
? r
->out
.error_string
:
1393 get_friendly_werror_msg(werr
));
1399 /*******************************************************************
1400 ********************************************************************/
1402 static int net_ads_dns_register(struct net_context
*c
, int argc
, const char **argv
)
1404 #if defined(WITH_DNS_UPDATES)
1410 talloc_enable_leak_report();
1413 if (argc
> 0 || c
->display_usage
) {
1414 d_printf(_("Usage:\n"
1415 "net ads dns register\n"
1416 " Register hostname with DNS\n"));
1420 if (!(ctx
= talloc_init("net_ads_dns"))) {
1421 d_fprintf(stderr
, _("Could not initialise talloc context\n"));
1425 status
= ads_startup(c
, true, &ads
);
1426 if ( !ADS_ERR_OK(status
) ) {
1427 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status
)));
1432 if ( !NT_STATUS_IS_OK(net_update_dns(ctx
, ads
)) ) {
1433 d_fprintf( stderr
, _("DNS update failed!\n") );
1434 ads_destroy( &ads
);
1439 d_fprintf( stderr
, _("Successfully registered hostname with DNS\n") );
1447 _("DNS update support not enabled at compile time!\n"));
1452 #if defined(WITH_DNS_UPDATES)
1453 DNS_ERROR
do_gethostbyname(const char *server
, const char *host
);
1456 static int net_ads_dns_gethostbyname(struct net_context
*c
, int argc
, const char **argv
)
1458 #if defined(WITH_DNS_UPDATES)
1462 talloc_enable_leak_report();
1465 if (argc
!= 2 || c
->display_usage
) {
1466 d_printf(_("Usage:\n"
1467 "net ads dns gethostbyname <server> <name>\n"
1468 " Look up hostname from the AD\n"
1469 " server\tName server to use\n"
1470 " name\tName to look up\n"));
1474 err
= do_gethostbyname(argv
[0], argv
[1]);
1476 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err
));
1481 static int net_ads_dns(struct net_context
*c
, int argc
, const char *argv
[])
1483 struct functable func
[] = {
1486 net_ads_dns_register
,
1488 N_("Add host dns entry to AD"),
1489 N_("net ads dns register\n"
1490 " Add host dns entry to AD")
1494 net_ads_dns_gethostbyname
,
1497 N_("net ads dns gethostbyname\n"
1500 {NULL
, NULL
, 0, NULL
, NULL
}
1503 return net_run_function(c
, argc
, argv
, "net ads dns", func
);
1506 /*******************************************************************
1507 ********************************************************************/
1509 int net_ads_printer_usage(struct net_context
*c
, int argc
, const char **argv
)
1512 "\nnet ads printer search <printer>"
1513 "\n\tsearch for a printer in the directory\n"
1514 "\nnet ads printer info <printer> <server>"
1515 "\n\tlookup info in directory for printer on server"
1516 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1517 "\nnet ads printer publish <printername>"
1518 "\n\tpublish printer in directory"
1519 "\n\t(note: printer name is required)\n"
1520 "\nnet ads printer remove <printername>"
1521 "\n\tremove printer from directory"
1522 "\n\t(note: printer name is required)\n"));
1526 /*******************************************************************
1527 ********************************************************************/
1529 static int net_ads_printer_search(struct net_context
*c
, int argc
, const char **argv
)
1533 LDAPMessage
*res
= NULL
;
1535 if (c
->display_usage
) {
1536 d_printf(_("Usage:\n"
1537 "net ads printer search\n"
1538 " List printers in the AD\n"));
1542 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1546 rc
= ads_find_printers(ads
, &res
);
1548 if (!ADS_ERR_OK(rc
)) {
1549 d_fprintf(stderr
, _("ads_find_printer: %s\n"), ads_errstr(rc
));
1550 ads_msgfree(ads
, res
);
1555 if (ads_count_replies(ads
, res
) == 0) {
1556 d_fprintf(stderr
, _("No results found\n"));
1557 ads_msgfree(ads
, res
);
1563 ads_msgfree(ads
, res
);
1568 static int net_ads_printer_info(struct net_context
*c
, int argc
, const char **argv
)
1572 const char *servername
, *printername
;
1573 LDAPMessage
*res
= NULL
;
1575 if (c
->display_usage
) {
1576 d_printf(_("Usage:\n"
1577 "net ads printer info [printername [servername]]\n"
1578 " Display printer info from AD\n"
1579 " printername\tPrinter name or wildcard\n"
1580 " servername\tName of the print server\n"));
1584 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
1589 printername
= argv
[0];
1595 servername
= argv
[1];
1597 servername
= global_myname();
1600 rc
= ads_find_printer_on_server(ads
, &res
, printername
, servername
);
1602 if (!ADS_ERR_OK(rc
)) {
1603 d_fprintf(stderr
, _("Server '%s' not found: %s\n"),
1604 servername
, ads_errstr(rc
));
1605 ads_msgfree(ads
, res
);
1610 if (ads_count_replies(ads
, res
) == 0) {
1611 d_fprintf(stderr
, _("Printer '%s' not found\n"), printername
);
1612 ads_msgfree(ads
, res
);
1618 ads_msgfree(ads
, res
);
1624 static int net_ads_printer_publish(struct net_context
*c
, int argc
, const char **argv
)
1628 const char *servername
, *printername
;
1629 struct cli_state
*cli
;
1630 struct rpc_pipe_client
*pipe_hnd
;
1631 struct sockaddr_storage server_ss
;
1633 TALLOC_CTX
*mem_ctx
= talloc_init("net_ads_printer_publish");
1634 ADS_MODLIST mods
= ads_init_mods(mem_ctx
);
1635 char *prt_dn
, *srv_dn
, **srv_cn
;
1636 char *srv_cn_escaped
= NULL
, *printername_escaped
= NULL
;
1637 LDAPMessage
*res
= NULL
;
1639 if (argc
< 1 || c
->display_usage
) {
1640 d_printf(_("Usage:\n"
1641 "net ads printer publish <printername> [servername]\n"
1642 " Publish printer in AD\n"
1643 " printername\tName of the printer\n"
1644 " servername\tName of the print server\n"));
1645 talloc_destroy(mem_ctx
);
1649 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1650 talloc_destroy(mem_ctx
);
1654 printername
= argv
[0];
1657 servername
= argv
[1];
1659 servername
= global_myname();
1662 /* Get printer data from SPOOLSS */
1664 resolve_name(servername
, &server_ss
, 0x20, false);
1666 nt_status
= cli_full_connection(&cli
, global_myname(), servername
,
1669 c
->opt_user_name
, c
->opt_workgroup
,
1670 c
->opt_password
? c
->opt_password
: "",
1671 CLI_FULL_CONNECTION_USE_KERBEROS
,
1674 if (NT_STATUS_IS_ERR(nt_status
)) {
1675 d_fprintf(stderr
, _("Unable to open a connnection to %s to "
1676 "obtain data for %s\n"),
1677 servername
, printername
);
1679 talloc_destroy(mem_ctx
);
1683 /* Publish on AD server */
1685 ads_find_machine_acct(ads
, &res
, servername
);
1687 if (ads_count_replies(ads
, res
) == 0) {
1688 d_fprintf(stderr
, _("Could not find machine account for server "
1692 talloc_destroy(mem_ctx
);
1696 srv_dn
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
1697 srv_cn
= ldap_explode_dn(srv_dn
, 1);
1699 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn
[0]);
1700 printername_escaped
= escape_rdn_val_string_alloc(printername
);
1701 if (!srv_cn_escaped
|| !printername_escaped
) {
1702 SAFE_FREE(srv_cn_escaped
);
1703 SAFE_FREE(printername_escaped
);
1704 d_fprintf(stderr
, _("Internal error, out of memory!"));
1706 talloc_destroy(mem_ctx
);
1710 if (asprintf(&prt_dn
, "cn=%s-%s,%s", srv_cn_escaped
, printername_escaped
, srv_dn
) == -1) {
1711 SAFE_FREE(srv_cn_escaped
);
1712 SAFE_FREE(printername_escaped
);
1713 d_fprintf(stderr
, _("Internal error, out of memory!"));
1715 talloc_destroy(mem_ctx
);
1719 SAFE_FREE(srv_cn_escaped
);
1720 SAFE_FREE(printername_escaped
);
1722 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_spoolss
.syntax_id
, &pipe_hnd
);
1723 if (!NT_STATUS_IS_OK(nt_status
)) {
1724 d_fprintf(stderr
, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1728 talloc_destroy(mem_ctx
);
1732 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd
, mem_ctx
, &mods
,
1736 talloc_destroy(mem_ctx
);
1740 rc
= ads_add_printer_entry(ads
, prt_dn
, mem_ctx
, &mods
);
1741 if (!ADS_ERR_OK(rc
)) {
1742 d_fprintf(stderr
, "ads_publish_printer: %s\n", ads_errstr(rc
));
1745 talloc_destroy(mem_ctx
);
1749 d_printf("published printer\n");
1752 talloc_destroy(mem_ctx
);
1757 static int net_ads_printer_remove(struct net_context
*c
, int argc
, const char **argv
)
1761 const char *servername
;
1763 LDAPMessage
*res
= NULL
;
1765 if (argc
< 1 || c
->display_usage
) {
1766 d_printf(_("Usage:\n"
1767 "net ads printer remove <printername> [servername]\n"
1768 " Remove a printer from the AD\n"
1769 " printername\tName of the printer\n"
1770 " servername\tName of the print server\n"));
1774 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1779 servername
= argv
[1];
1781 servername
= global_myname();
1784 rc
= ads_find_printer_on_server(ads
, &res
, argv
[0], servername
);
1786 if (!ADS_ERR_OK(rc
)) {
1787 d_fprintf(stderr
, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc
));
1788 ads_msgfree(ads
, res
);
1793 if (ads_count_replies(ads
, res
) == 0) {
1794 d_fprintf(stderr
, _("Printer '%s' not found\n"), argv
[1]);
1795 ads_msgfree(ads
, res
);
1800 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
1801 ads_msgfree(ads
, res
);
1802 rc
= ads_del_dn(ads
, prt_dn
);
1803 TALLOC_FREE(prt_dn
);
1805 if (!ADS_ERR_OK(rc
)) {
1806 d_fprintf(stderr
, _("ads_del_dn: %s\n"), ads_errstr(rc
));
1815 static int net_ads_printer(struct net_context
*c
, int argc
, const char **argv
)
1817 struct functable func
[] = {
1820 net_ads_printer_search
,
1822 N_("Search for a printer"),
1823 N_("net ads printer search\n"
1824 " Search for a printer")
1828 net_ads_printer_info
,
1830 N_("Display printer information"),
1831 N_("net ads printer info\n"
1832 " Display printer information")
1836 net_ads_printer_publish
,
1838 N_("Publish a printer"),
1839 N_("net ads printer publish\n"
1840 " Publish a printer")
1844 net_ads_printer_remove
,
1846 N_("Delete a printer"),
1847 N_("net ads printer remove\n"
1848 " Delete a printer")
1850 {NULL
, NULL
, 0, NULL
, NULL
}
1853 return net_run_function(c
, argc
, argv
, "net ads printer", func
);
1857 static int net_ads_password(struct net_context
*c
, int argc
, const char **argv
)
1860 const char *auth_principal
= c
->opt_user_name
;
1861 const char *auth_password
= c
->opt_password
;
1863 char *new_password
= NULL
;
1868 if (c
->display_usage
) {
1869 d_printf(_("Usage:\n"
1870 "net ads password <username>\n"
1871 " Change password for user\n"
1872 " username\tName of user to change password for\n"));
1876 if (c
->opt_user_name
== NULL
|| c
->opt_password
== NULL
) {
1877 d_fprintf(stderr
, _("You must supply an administrator "
1878 "username/password\n"));
1883 d_fprintf(stderr
, _("ERROR: You must say which username to "
1884 "change password for\n"));
1889 if (!strchr_m(user
, '@')) {
1890 if (asprintf(&chr
, "%s@%s", argv
[0], lp_realm()) == -1) {
1896 use_in_memory_ccache();
1897 chr
= strchr_m(auth_principal
, '@');
1904 /* use the realm so we can eventually change passwords for users
1905 in realms other than default */
1906 if (!(ads
= ads_init(realm
, c
->opt_workgroup
, c
->opt_host
))) {
1910 /* we don't actually need a full connect, but it's the easy way to
1911 fill in the KDC's addresss */
1914 if (!ads
->config
.realm
) {
1915 d_fprintf(stderr
, _("Didn't find the kerberos server!\n"));
1921 new_password
= (char *)argv
[1];
1923 if (asprintf(&prompt
, _("Enter new password for %s:"), user
) == -1) {
1926 new_password
= getpass(prompt
);
1930 ret
= kerberos_set_password(ads
->auth
.kdc_server
, auth_principal
,
1931 auth_password
, user
, new_password
, ads
->auth
.time_offset
);
1932 if (!ADS_ERR_OK(ret
)) {
1933 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
1938 d_printf(_("Password change for %s completed.\n"), user
);
1944 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
1947 char *host_principal
;
1951 if (c
->display_usage
) {
1952 d_printf(_("Usage:\n"
1953 "net ads changetrustpw\n"
1954 " Change the machine account's trust password\n"));
1958 if (!secrets_init()) {
1959 DEBUG(1,("Failed to initialise secrets database\n"));
1963 net_use_krb_machine_account(c
);
1965 use_in_memory_ccache();
1967 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
1971 fstrcpy(my_name
, global_myname());
1972 strlower_m(my_name
);
1973 if (asprintf(&host_principal
, "%s$@%s", my_name
, ads
->config
.realm
) == -1) {
1977 d_printf(_("Changing password for principal: %s\n"), host_principal
);
1979 ret
= ads_change_trust_account_password(ads
, host_principal
);
1981 if (!ADS_ERR_OK(ret
)) {
1982 d_fprintf(stderr
, _("Password change failed: %s\n"), ads_errstr(ret
));
1984 SAFE_FREE(host_principal
);
1988 d_printf(_("Password change for principal %s succeeded.\n"), host_principal
);
1990 if (USE_SYSTEM_KEYTAB
) {
1991 d_printf(_("Attempting to update system keytab with new password.\n"));
1992 if (ads_keytab_create_default(ads
)) {
1993 d_printf(_("Failed to update system keytab.\n"));
1998 SAFE_FREE(host_principal
);
2004 help for net ads search
2006 static int net_ads_search_usage(struct net_context
*c
, int argc
, const char **argv
)
2009 "\nnet ads search <expression> <attributes...>\n"
2010 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2011 "The expression is a standard LDAP search expression, and the\n"
2012 "attributes are a list of LDAP fields to show in the results.\n\n"
2013 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2015 net_common_flags_usage(c
, argc
, argv
);
2021 general ADS search function. Useful in diagnosing problems in ADS
2023 static int net_ads_search(struct net_context
*c
, int argc
, const char **argv
)
2027 const char *ldap_exp
;
2029 LDAPMessage
*res
= NULL
;
2031 if (argc
< 1 || c
->display_usage
) {
2032 return net_ads_search_usage(c
, argc
, argv
);
2035 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2042 rc
= ads_do_search_all(ads
, ads
->config
.bind_path
,
2044 ldap_exp
, attrs
, &res
);
2045 if (!ADS_ERR_OK(rc
)) {
2046 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2051 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2053 /* dump the results */
2056 ads_msgfree(ads
, res
);
2064 help for net ads search
2066 static int net_ads_dn_usage(struct net_context
*c
, int argc
, const char **argv
)
2069 "\nnet ads dn <dn> <attributes...>\n"
2070 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2071 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2072 "to show in the results\n\n"
2073 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2074 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2076 net_common_flags_usage(c
, argc
, argv
);
2082 general ADS search function. Useful in diagnosing problems in ADS
2084 static int net_ads_dn(struct net_context
*c
, int argc
, const char **argv
)
2090 LDAPMessage
*res
= NULL
;
2092 if (argc
< 1 || c
->display_usage
) {
2093 return net_ads_dn_usage(c
, argc
, argv
);
2096 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2103 rc
= ads_do_search_all(ads
, dn
,
2105 "(objectclass=*)", attrs
, &res
);
2106 if (!ADS_ERR_OK(rc
)) {
2107 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2112 d_printf("Got %d replies\n\n", ads_count_replies(ads
, res
));
2114 /* dump the results */
2117 ads_msgfree(ads
, res
);
2124 help for net ads sid search
2126 static int net_ads_sid_usage(struct net_context
*c
, int argc
, const char **argv
)
2129 "\nnet ads sid <sid> <attributes...>\n"
2130 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2131 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2132 "to show in the results\n\n"
2133 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2135 net_common_flags_usage(c
, argc
, argv
);
2141 general ADS search function. Useful in diagnosing problems in ADS
2143 static int net_ads_sid(struct net_context
*c
, int argc
, const char **argv
)
2147 const char *sid_string
;
2149 LDAPMessage
*res
= NULL
;
2152 if (argc
< 1 || c
->display_usage
) {
2153 return net_ads_sid_usage(c
, argc
, argv
);
2156 if (!ADS_ERR_OK(ads_startup(c
, false, &ads
))) {
2160 sid_string
= argv
[0];
2163 if (!string_to_sid(&sid
, sid_string
)) {
2164 d_fprintf(stderr
, _("could not convert sid\n"));
2169 rc
= ads_search_retry_sid(ads
, &res
, &sid
, attrs
);
2170 if (!ADS_ERR_OK(rc
)) {
2171 d_fprintf(stderr
, _("search failed: %s\n"), ads_errstr(rc
));
2176 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads
, res
));
2178 /* dump the results */
2181 ads_msgfree(ads
, res
);
2187 static int net_ads_keytab_flush(struct net_context
*c
, int argc
, const char **argv
)
2192 if (c
->display_usage
) {
2193 d_printf(_("Usage:\n"
2194 "net ads keytab flush\n"
2195 " Delete the whole keytab\n"));
2199 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2202 ret
= ads_keytab_flush(ads
);
2207 static int net_ads_keytab_add(struct net_context
*c
, int argc
, const char **argv
)
2213 if (c
->display_usage
) {
2214 d_printf(_("Usage:\n"
2215 "net ads keytab add <principal> [principal ...]\n"
2216 " Add principals to local keytab\n"
2217 " principal\tKerberos principal to add to "
2222 d_printf(_("Processing principals to add...\n"));
2223 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2226 for (i
= 0; i
< argc
; i
++) {
2227 ret
|= ads_keytab_add_entry(ads
, argv
[i
]);
2233 static int net_ads_keytab_create(struct net_context
*c
, int argc
, const char **argv
)
2238 if (c
->display_usage
) {
2239 d_printf(_("Usage:\n"
2240 "net ads keytab create\n"
2241 " Create new default keytab\n"));
2245 if (!ADS_ERR_OK(ads_startup(c
, true, &ads
))) {
2248 ret
= ads_keytab_create_default(ads
);
2253 static int net_ads_keytab_list(struct net_context
*c
, int argc
, const char **argv
)
2255 const char *keytab
= NULL
;
2257 if (c
->display_usage
) {
2258 d_printf(_("Usage:\n"
2259 "net ads keytab list [keytab]\n"
2260 " List a local keytab\n"
2261 " keytab\tKeytab to list\n"));
2269 return ads_keytab_list(keytab
);
2273 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2275 struct functable func
[] = {
2280 N_("Add a service principal"),
2281 N_("net ads keytab add\n"
2282 " Add a service principal")
2286 net_ads_keytab_create
,
2288 N_("Create a fresh keytab"),
2289 N_("net ads keytab create\n"
2290 " Create a fresh keytab")
2294 net_ads_keytab_flush
,
2296 N_("Remove all keytab entries"),
2297 N_("net ads keytab flush\n"
2298 " Remove all keytab entries")
2302 net_ads_keytab_list
,
2304 N_("List a keytab"),
2305 N_("net ads keytab list\n"
2308 {NULL
, NULL
, 0, NULL
, NULL
}
2311 if (!USE_KERBEROS_KEYTAB
) {
2312 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2313 "keytab method to use keytab functions.\n"));
2316 return net_run_function(c
, argc
, argv
, "net ads keytab", func
);
2319 static int net_ads_kerberos_renew(struct net_context
*c
, int argc
, const char **argv
)
2323 if (c
->display_usage
) {
2324 d_printf(_("Usage:\n"
2325 "net ads kerberos renew\n"
2326 " Renew TGT from existing credential cache\n"));
2330 ret
= smb_krb5_renew_ticket(NULL
, NULL
, NULL
, NULL
);
2332 d_printf(_("failed to renew kerberos ticket: %s\n"),
2333 error_message(ret
));
2338 static int net_ads_kerberos_pac(struct net_context
*c
, int argc
, const char **argv
)
2340 struct PAC_DATA
*pac
= NULL
;
2341 struct PAC_LOGON_INFO
*info
= NULL
;
2342 TALLOC_CTX
*mem_ctx
= NULL
;
2346 if (c
->display_usage
) {
2347 d_printf(_("Usage:\n"
2348 "net ads kerberos pac\n"
2349 " Dump the Kerberos PAC\n"));
2353 mem_ctx
= talloc_init("net_ads_kerberos_pac");
2358 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2360 status
= kerberos_return_pac(mem_ctx
,
2369 2592000, /* one month */
2371 if (!NT_STATUS_IS_OK(status
)) {
2372 d_printf(_("failed to query kerberos PAC: %s\n"),
2377 info
= get_logon_info_from_pac(pac
);
2380 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, PAC_LOGON_INFO
, info
);
2381 d_printf(_("The Pac: %s\n"), s
);
2386 TALLOC_FREE(mem_ctx
);
2390 static int net_ads_kerberos_kinit(struct net_context
*c
, int argc
, const char **argv
)
2392 TALLOC_CTX
*mem_ctx
= NULL
;
2396 if (c
->display_usage
) {
2397 d_printf(_("Usage:\n"
2398 "net ads kerberos kinit\n"
2399 " Get Ticket Granting Ticket (TGT) for the user\n"));
2403 mem_ctx
= talloc_init("net_ads_kerberos_kinit");
2408 c
->opt_password
= net_prompt_pass(c
, c
->opt_user_name
);
2410 ret
= kerberos_kinit_password_ext(c
->opt_user_name
,
2418 2592000, /* one month */
2421 d_printf(_("failed to kinit password: %s\n"),
2428 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2430 struct functable func
[] = {
2433 net_ads_kerberos_kinit
,
2435 N_("Retrieve Ticket Granting Ticket (TGT)"),
2436 N_("net ads kerberos kinit\n"
2437 " Receive Ticket Granting Ticket (TGT)")
2441 net_ads_kerberos_renew
,
2443 N_("Renew Ticket Granting Ticket from credential cache"),
2444 N_("net ads kerberos renew\n"
2445 " Renew Ticket Granting Ticket (TGT) from "
2450 net_ads_kerberos_pac
,
2452 N_("Dump Kerberos PAC"),
2453 N_("net ads kerberos pac\n"
2454 " Dump Kerberos PAC")
2456 {NULL
, NULL
, 0, NULL
, NULL
}
2459 return net_run_function(c
, argc
, argv
, "net ads kerberos", func
);
2462 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2464 struct functable func
[] = {
2469 N_("Display details on remote ADS server"),
2471 " Display details on remote ADS server")
2477 N_("Join the local machine to ADS realm"),
2479 " Join the local machine to ADS realm")
2485 N_("Validate machine account"),
2486 N_("net ads testjoin\n"
2487 " Validate machine account")
2493 N_("Remove the local machine from ADS"),
2494 N_("net ads leave\n"
2495 " Remove the local machine from ADS")
2501 N_("Display machine account details"),
2502 N_("net ads status\n"
2503 " Display machine account details")
2509 N_("List/modify users"),
2511 " List/modify users")
2517 N_("List/modify groups"),
2518 N_("net ads group\n"
2519 " List/modify groups")
2525 N_("Issue dynamic DNS update"),
2527 " Issue dynamic DNS update")
2533 N_("Change user passwords"),
2534 N_("net ads password\n"
2535 " Change user passwords")
2539 net_ads_changetrustpw
,
2541 N_("Change trust account password"),
2542 N_("net ads changetrustpw\n"
2543 " Change trust account password")
2549 N_("List/modify printer entries"),
2550 N_("net ads printer\n"
2551 " List/modify printer entries")
2557 N_("Issue LDAP search using filter"),
2558 N_("net ads search\n"
2559 " Issue LDAP search using filter")
2565 N_("Issue LDAP search by DN"),
2567 " Issue LDAP search by DN")
2573 N_("Issue LDAP search by SID"),
2575 " Issue LDAP search by SID")
2581 N_("Display workgroup name"),
2582 N_("net ads workgroup\n"
2583 " Display the workgroup name")
2589 N_("Perfom CLDAP query on DC"),
2590 N_("net ads lookup\n"
2591 " Find the ADS DC using CLDAP lookups")
2597 N_("Manage local keytab file"),
2598 N_("net ads keytab\n"
2599 " Manage local keytab file")
2605 N_("Manage group policy objects"),
2607 " Manage group policy objects")
2613 N_("Manage kerberos keytab"),
2614 N_("net ads kerberos\n"
2615 " Manage kerberos keytab")
2617 {NULL
, NULL
, 0, NULL
, NULL
}
2620 return net_run_function(c
, argc
, argv
, "net ads", func
);
2625 static int net_ads_noads(void)
2627 d_fprintf(stderr
, _("ADS support not compiled in\n"));
2631 int net_ads_keytab(struct net_context
*c
, int argc
, const char **argv
)
2633 return net_ads_noads();
2636 int net_ads_kerberos(struct net_context
*c
, int argc
, const char **argv
)
2638 return net_ads_noads();
2641 int net_ads_changetrustpw(struct net_context
*c
, int argc
, const char **argv
)
2643 return net_ads_noads();
2646 int net_ads_join(struct net_context
*c
, int argc
, const char **argv
)
2648 return net_ads_noads();
2651 int net_ads_user(struct net_context
*c
, int argc
, const char **argv
)
2653 return net_ads_noads();
2656 int net_ads_group(struct net_context
*c
, int argc
, const char **argv
)
2658 return net_ads_noads();
2661 /* this one shouldn't display a message */
2662 int net_ads_check(struct net_context
*c
)
2667 int net_ads_check_our_domain(struct net_context
*c
)
2672 int net_ads(struct net_context
*c
, int argc
, const char **argv
)
2674 return net_ads_noads();
2677 #endif /* WITH_ADS */