Ejemplo n.º 1
0
static int net_ads_printer_search(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	void *res = NULL;

	if (!(ads = ads_startup())) {
		return -1;
	}

	rc = ads_find_printers(ads, &res);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_find_printer: %s\n", ads_errstr(rc));
		ads_msgfree(ads, res);
		ads_destroy(&ads);
	 	return -1;
	}

	if (ads_count_replies(ads, res) == 0) {
		d_printf("No results found\n");
		ads_msgfree(ads, res);
		ads_destroy(&ads);
		return -1;
	}

	ads_dump(ads, res);
	ads_msgfree(ads, res);
	ads_destroy(&ads);
	return 0;
}
Ejemplo n.º 2
0
static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
                                       const char *printer)
{
	ADS_STATUS ads_rc;
	LDAPMessage *res = NULL;
	char *prt_dn = NULL;

	DEBUG(5, ("unpublishing printer %s\n", printer));

	/* remove the printer from the directory */
	ads_rc = ads_find_printer_on_server(ads, &res,
					    printer, lp_netbios_name());

	if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
		prt_dn = ads_get_dn(ads, talloc_tos(), res);
		if (!prt_dn) {
			ads_msgfree(ads, res);
			return WERR_NOMEM;
		}
		ads_rc = ads_del_dn(ads, prt_dn);
		TALLOC_FREE(prt_dn);
	}

	if (res) {
		ads_msgfree(ads, res);
	}
	return WERR_OK;
}
Ejemplo n.º 3
0
static int net_ads_printer_remove(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	const char *servername;
	char *prt_dn;
	void *res = NULL;

	if (!(ads = ads_startup())) {
		return -1;
	}

	if (argc < 1) {
		return net_ads_printer_usage(argc, argv);
	}

	if (argc > 1) {
		servername = argv[1];
	} else {
		servername = global_myname();
	}

	rc = ads_find_printer_on_server(ads, &res, argv[0], servername);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
		ads_msgfree(ads, res);
		ads_destroy(&ads);
		return -1;
	}

	if (ads_count_replies(ads, res) == 0) {
		d_printf("Printer '%s' not found\n", argv[1]);
		ads_msgfree(ads, res);
		ads_destroy(&ads);
		return -1;
	}

	prt_dn = ads_get_dn(ads, res);
	ads_msgfree(ads, res);
	rc = ads_del_dn(ads, prt_dn);
	ads_memfree(ads, prt_dn);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_del_dn: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}

	ads_destroy(&ads);
	return 0;
}
Ejemplo n.º 4
0
static int ads_group_delete(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	void *res;
	char *groupdn;

	if (argc < 1) {
		return net_ads_group_usage(argc, argv);
	}
	
	if (!(ads = ads_startup())) {
		return -1;
	}

	rc = ads_find_user_acct(ads, &res, argv[0]);
	if (!ADS_ERR_OK(rc)) {
		DEBUG(0, ("Group %s does not exist\n", argv[0]));
		ads_destroy(&ads);
		return -1;
	}
	groupdn = ads_get_dn(ads, res);
	ads_msgfree(ads, res);
	rc = ads_del_dn(ads, groupdn);
	ads_memfree(ads, groupdn);
	if (!ADS_ERR_OK(rc)) {
		d_printf("Group %s deleted\n", argv[0]);
		ads_destroy(&ads);
		return 0;
	}
	d_printf("Error deleting group %s: %s\n", argv[0], 
		 ads_errstr(rc));
	ads_destroy(&ads);
	return -1;
}
Ejemplo n.º 5
0
static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads,
						const char *printer_dn,
						struct GUID *pguid)
{
	ADS_STATUS ads_status;
	LDAPMessage *res;
	const char *attrs[] = {"objectGUID", NULL};
	struct GUID guid;
	bool ok;

	ads_status = ads_search_dn(ads, &res, printer_dn, attrs);
	if (!ADS_ERR_OK(ads_status)) {
		DEBUG(2, ("Failed to retrieve GUID from DC - %s\n",
			  ads_errstr(ads_status)));
		return WERR_BADFILE;
	}

	ZERO_STRUCT(guid);
	ok = ads_pull_guid(ads, res, &guid);
	ads_msgfree(ads, res);
	if (!ok) {
		return WERR_NOMEM;
	}

	*pguid = guid;

	return WERR_OK;
}
Ejemplo n.º 6
0
/* convert a sid to a user or group name */
NTSTATUS ads_sid_to_name(ADS_STRUCT *ads,
			 TALLOC_CTX *mem_ctx,
			 const DOM_SID *sid,
			 char **name,
			 enum SID_NAME_USE *type)
{
	const char *attrs[] = {"userPrincipalName", 
			       "sAMAccountName",
			       "sAMAccountType", NULL};
	ADS_STATUS rc;
	void *msg = NULL;
	char *ldap_exp = NULL;
	char *sidstr = NULL;
	uint32 atype;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;

	if (!(sidstr = sid_binstring(sid))) {
		DEBUG(1,("ads_sid_to_name: sid_binstring failed!\n"));
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
		DEBUG(1,("ads_sid_to_name: asprintf failed!\n"));
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	if (!ADS_ERR_OK(rc)) {
		status = ads_ntstatus(rc);
		DEBUG(1,("ads_sid_to_name ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
		goto done;
	}

	*name = ads_pull_username(ads, mem_ctx, msg);
	if (!*name) {
		DEBUG(1,("ads_sid_to_name: ads_pull_username retuned NULL!\n"));
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
		
	*type = ads_atype_map(atype);

	status = NT_STATUS_OK;

	DEBUG(3,("ads sid_to_name mapped %s\n", *name));

done:
	if (msg) ads_msgfree(ads, msg);

	SAFE_FREE(ldap_exp);
	SAFE_FREE(sidstr);

	return status;
}
Ejemplo n.º 7
0
/*
  find a printer given the name and the hostname
    Note that results "res" may be allocated on return so that the
    results can be used.  It should be freed using ads_msgfree.
*/
 ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, LDAPMessage **res,
				       const char *printer,
				       const char *servername)
{
	ADS_STATUS status;
	char *srv_dn, **srv_cn, *s = NULL;
	const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};

	status = ads_find_machine_acct(ads, res, servername);
	if (!ADS_ERR_OK(status)) {
		DEBUG(1, ("ads_find_printer_on_server: cannot find host %s in ads\n",
			  servername));
		return status;
	}
	if (ads_count_replies(ads, *res) != 1) {
		ads_msgfree(ads, *res);
		*res = NULL;
		return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
	}
	srv_dn = ldap_get_dn(ads->ldap.ld, *res);
	if (srv_dn == NULL) {
		ads_msgfree(ads, *res);
		*res = NULL;
		return ADS_ERROR(LDAP_NO_MEMORY);
	}
	srv_cn = ldap_explode_dn(srv_dn, 1);
	if (srv_cn == NULL) {
		ldap_memfree(srv_dn);
		ads_msgfree(ads, *res);
		*res = NULL;
		return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
	}
	ads_msgfree(ads, *res);
	*res = NULL;

	if (asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer) == -1) {
		ldap_memfree(srv_dn);
		return ADS_ERROR(LDAP_NO_MEMORY);
	}
	status = ads_search(ads, res, s, attrs);

	ldap_memfree(srv_dn);
	ldap_value_free(srv_cn);
	SAFE_FREE(s);
	return status;	
}
Ejemplo n.º 8
0
static int net_ads_printer_info(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	const char *servername, *printername;
	void *res = NULL;

	if (!(ads = ads_startup())) {
		return -1;
	}

	if (argc > 0) {
		printername = argv[0];
	} else {
		printername = "*";
	}

	if (argc > 1) {
		servername =  argv[1];
	} else {
		servername = global_myname();
	}

	rc = ads_find_printer_on_server(ads, &res, printername, servername);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
		ads_msgfree(ads, res);
		ads_destroy(&ads);
		return -1;
	}

	if (ads_count_replies(ads, res) == 0) {
		d_printf("Printer '%s' not found\n", printername);
		ads_msgfree(ads, res);
		ads_destroy(&ads);
		return -1;
	}

	ads_dump(ads, res);
	ads_msgfree(ads, res);
	ads_destroy(&ads);

	return 0;
}
Ejemplo n.º 9
0
static int ads_group_add(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS status;
	void *res=NULL;
	int rc = -1;

	if (argc < 1) {
		return net_ads_group_usage(argc, argv);
	}
	
	if (!(ads = ads_startup())) {
		return -1;
	}

	status = ads_find_user_acct(ads, &res, argv[0]);

	if (!ADS_ERR_OK(status)) {
		d_printf("ads_group_add: %s\n", ads_errstr(status));
		goto done;
	}
	
	if (ads_count_replies(ads, res)) {
		d_printf("ads_group_add: Group %s already exists\n", argv[0]);
		ads_msgfree(ads, res);
		goto done;
	}

	status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment);

	if (ADS_ERR_OK(status)) {
		d_printf("Group %s added\n", argv[0]);
		rc = 0;
	} else {
		d_printf("Could not add group %s: %s\n", argv[0],
			 ads_errstr(status));
	}

 done:
	if (res)
		ads_msgfree(ads, res);
	ads_destroy(&ads);
	return rc;
}
Ejemplo n.º 10
0
static int ads_user_info(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	void *res;
	const char *attrs[] = {"memberOf", NULL};
	char *searchstring=NULL;
	char **grouplist;
	char *escaped_user = escape_ldap_string_alloc(argv[0]);

	if (argc < 1) {
		return net_ads_user_usage(argc, argv);
	}
	
	if (!(ads = ads_startup())) {
		return -1;
	}

	if (!escaped_user) {
		d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
		ads_destroy(&ads);
	 	return -1;
	}

	asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
	rc = ads_search(ads, &res, searchstring, attrs);
	safe_free(searchstring);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_search: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}
	
	grouplist = ldap_get_values(ads->ld, res, "memberOf");

	if (grouplist) {
		int i;
		char **groupname;
		for (i=0;grouplist[i];i++) {
			groupname = ldap_explode_dn(grouplist[i], 1);
			d_printf("%s\n", groupname[0]);
			ldap_value_free(groupname);
		}
		ldap_value_free(grouplist);
	}
	
	ads_msgfree(ads, res);
	ads_destroy(&ads);
	return 0;
}
Ejemplo n.º 11
0
/*
  general ADS search function. Useful in diagnosing problems in ADS
*/
static int net_ads_dn(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	const char *dn;
	const char **attrs;
	void *res = NULL;

	if (argc < 1) {
		return net_ads_dn_usage(argc, argv);
	}

	if (!(ads = ads_startup())) {
		return -1;
	}

	dn = argv[0];
	attrs = (argv + 1);

	rc = ads_do_search_all(ads, dn, 
			       LDAP_SCOPE_BASE,
			       "(objectclass=*)", attrs, &res);
	if (!ADS_ERR_OK(rc)) {
		d_printf("search failed: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}	

	d_printf("Got %d replies\n\n", ads_count_replies(ads, res));

	/* dump the results */
	ads_dump(ads, res);

	ads_msgfree(ads, res);
	ads_destroy(&ads);

	return 0;
}
Ejemplo n.º 12
0
/*
  general ADS search function. Useful in diagnosing problems in ADS
*/
static int net_ads_search(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	const char *ldap_exp;
	const char **attrs;
	void *res = NULL;

	if (argc < 1) {
		return net_ads_search_usage(argc, argv);
	}

	if (!(ads = ads_startup())) {
		return -1;
	}

	ldap_exp = argv[0];
	attrs = (argv + 1);

	rc = ads_do_search_all(ads, ads->config.bind_path,
			       LDAP_SCOPE_SUBTREE,
			       ldap_exp, attrs, &res);
	if (!ADS_ERR_OK(rc)) {
		d_printf("search failed: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}	

	d_printf("Got %d replies\n\n", ads_count_replies(ads, res));

	/* dump the results */
	ads_dump(ads, res);

	ads_msgfree(ads, res);
	ads_destroy(&ads);

	return 0;
}
Ejemplo n.º 13
0
static int ads_user_add(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS status;
	char *upn, *userdn;
	void *res=NULL;
	int rc = -1;

	if (argc < 1) return net_ads_user_usage(argc, argv);
	
	if (!(ads = ads_startup())) {
		return -1;
	}

	status = ads_find_user_acct(ads, &res, argv[0]);

	if (!ADS_ERR_OK(status)) {
		d_printf("ads_user_add: %s\n", ads_errstr(status));
		goto done;
	}
	
	if (ads_count_replies(ads, res)) {
		d_printf("ads_user_add: User %s already exists\n", argv[0]);
		goto done;
	}

	status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment);

	if (!ADS_ERR_OK(status)) {
		d_printf("Could not add user %s: %s\n", argv[0],
			 ads_errstr(status));
		goto done;
	}

	/* if no password is to be set, we're done */
	if (argc == 1) { 
		d_printf("User %s added\n", argv[0]);
		rc = 0;
		goto done;
	}

	/* try setting the password */
	asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
	status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], 
				       ads->auth.time_offset);
	safe_free(upn);
	if (ADS_ERR_OK(status)) {
		d_printf("User %s added\n", argv[0]);
		rc = 0;
		goto done;
	}

	/* password didn't set, delete account */
	d_printf("Could not add user %s.  Error setting password %s\n",
		 argv[0], ads_errstr(status));
	ads_msgfree(ads, res);
	status=ads_find_user_acct(ads, &res, argv[0]);
	if (ADS_ERR_OK(status)) {
		userdn = ads_get_dn(ads, res);
		ads_del_dn(ads, userdn);
		ads_memfree(ads, userdn);
	}

 done:
	if (res)
		ads_msgfree(ads, res);
	ads_destroy(&ads);
	return rc;
}
Ejemplo n.º 14
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const DOM_SID *sid, 
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;
	info->primary_gid = (gid_t)-1;

	/* try netsamlogon cache first */

	if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		status = NT_STATUS_OK;
		goto done;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	sidstr = sid_binstring(talloc_tos(), sid);
	if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	free(ldap_exp);
	TALLOC_FREE(sidstr);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;

	if (info->full_name == NULL) {
		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
	}

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
done:
	if (msg) 
		ads_msgfree(ads, msg);

	return status;
}
Ejemplo n.º 15
0
/*
  a wrapper around ldap_search_s that retries depending on the error code
  this is supposed to catch dropped connections and auto-reconnect
*/
ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope, 
			       const char *expr,
			       const char **attrs, void **res)
{
	ADS_STATUS status;
	int count = 3;
	char *bp;

	*res = NULL;

	if (!ads->ld &&
	    time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) {
		return ADS_ERROR(LDAP_SERVER_DOWN);
	}

	bp = strdup(bind_path);

	if (!bp) {
		return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
	}

	while (count--) {
		*res = NULL;
		status = ads_do_search_all(ads, bp, scope, expr, attrs, res);
		if (ADS_ERR_OK(status)) {
			DEBUG(5,("Search for %s gave %d replies\n",
				 expr, ads_count_replies(ads, *res)));
			SAFE_FREE(bp);
			return status;
		}

		if (*res) 
			ads_msgfree(ads, *res);
		*res = NULL;
		
		DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", 
			 ads->config.realm, ads_errstr(status)));
			 
		if (ads->ld) {
			ldap_unbind(ads->ld); 
		}
		
		ads->ld = NULL;
		status = ads_connect(ads);
		
		if (!ADS_ERR_OK(status)) {
			DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
				 ads_errstr(status)));
			ads_destroy(&ads);
			SAFE_FREE(bp);
			return status;
		}
	}
        SAFE_FREE(bp);

	if (!ADS_ERR_OK(status))
		DEBUG(1,("ads reopen failed after error %s\n", 
			 ads_errstr(status)));

	return status;
}
Ejemplo n.º 16
0
/* Lookup groups a user is a member of. */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
				  TALLOC_CTX *mem_ctx,
				  const struct dom_sid *sid,
				  uint32 *p_num_groups, struct dom_sid **user_sids)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *user_dn = NULL;
	struct dom_sid *sids;
	int i;
	struct dom_sid primary_group;
	uint32 primary_group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	uint32_t num_groups = 0;

	DEBUG(3,("ads: lookup_usergroups\n"));
	*p_num_groups = 0;

	status = lookup_usergroups_cached(domain, mem_ctx, sid, 
					  p_num_groups, user_sids);
	if (NT_STATUS_IS_OK(status)) {
		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
			  domain->name));

		/* Tell the cache manager not to remember this one */

		return NT_STATUS_SYNCHRONIZATION_REQUIRED;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry_sid(ads, &msg, sid, attrs);

	if (!ADS_ERR_OK(rc)) {
		status = ads_ntstatus(rc);
		DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
			  "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		status = NT_STATUS_UNSUCCESSFUL;
		DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
			 "invalid number of results (count=%d)\n", 
			 sid_string_dbg(sid), count));
		goto done;
	}

	if (!msg) {
		DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
			 sid_string_dbg(sid)));
		status = NT_STATUS_UNSUCCESSFUL;
		goto done;
	}

	user_dn = ads_get_dn(ads, mem_ctx, msg);
	if (user_dn == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
		DEBUG(1,("%s: No primary group for sid=%s !?\n", 
			 domain->name, sid_string_dbg(sid)));
		goto done;
	}

	sid_compose(&primary_group, &domain->sid, primary_group_rid);

	count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);

	/* there must always be at least one group in the token, 
	   unless we are talking to a buggy Win2k server */

	/* actually this only happens when the machine account has no read
	 * permissions on the tokenGroup attribute - gd */

	if (count == 0) {

		/* no tokenGroups */

		/* lookup what groups this user is a member of by DN search on
		 * "memberOf" */

		status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
						    &primary_group,
						    &num_groups, user_sids);
		*p_num_groups = num_groups;
		if (NT_STATUS_IS_OK(status)) {
			goto done;
		}

		/* lookup what groups this user is a member of by DN search on
		 * "member" */

		status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
						  &primary_group,
						  &num_groups, user_sids);
		*p_num_groups = num_groups;
		goto done;
	}

	*user_sids = NULL;
	num_groups = 0;

	status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
				  &num_groups);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	for (i=0;i<count;i++) {

		/* ignore Builtin groups from ADS - Guenther */
		if (sid_check_is_in_builtin(&sids[i])) {
			continue;
		}

		status = add_sid_to_array_unique(mem_ctx, &sids[i],
						 user_sids, &num_groups);
		if (!NT_STATUS_IS_OK(status)) {
			goto done;
		}
	}

	*p_num_groups = (uint32)num_groups;
	status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;

	DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
		 sid_string_dbg(sid)));
done:
	TALLOC_FREE(user_dn);
	ads_msgfree(ads, msg);
	return status;
}
Ejemplo n.º 17
0
static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads,
				      TALLOC_CTX *mem_ctx,
				      int scope,
				      const char *base,
				      const char *filter,
				      const char **attrs,
				      void *args,
				      const char *range_attr,
				      char ***strings,
				      size_t *num_strings,
				      uint32_t *first_usn,
				      int *num_retries,
				      bool *more_values)
{
	LDAPMessage *res = NULL;
	ADS_STATUS status;
	int count;
	uint32_t current_usn;

	DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1]));

	*more_values = False;

	status = ads_do_search_retry_internal(ads, base, scope, filter, attrs, args, &res);

	if (!ADS_ERR_OK(status)) {
		DEBUG(1,("ads_search: %s\n",
			 ads_errstr(status)));
		return status;
	}

	if (!res) {
		return ADS_ERROR(LDAP_NO_MEMORY);
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		ads_msgfree(ads, res);
		return ADS_ERROR(LDAP_SUCCESS);
	}

	if (*num_strings == 0) {
		if (!ads_pull_uint32(ads, res, "usnChanged", first_usn)) {
			DEBUG(1, ("could not pull first usnChanged!\n"));
			ads_msgfree(ads, res);
			return ADS_ERROR(LDAP_NO_MEMORY);
		}
	}

	if (!ads_pull_uint32(ads, res, "usnChanged", &current_usn)) {
		DEBUG(1, ("could not pull current usnChanged!\n"));
		ads_msgfree(ads, res);
		return ADS_ERROR(LDAP_NO_MEMORY);
	}

	if (*first_usn != current_usn) {
		DEBUG(5, ("USN on this record changed"
			  " - restarting search\n"));
		if (*num_retries < 5) {
			(*num_retries)++;
			*num_strings = 0;
			ads_msgfree(ads, res);
			return ADS_ERROR_NT(STATUS_MORE_ENTRIES);
		} else {
			DEBUG(5, ("USN on this record changed"
				  " - restarted search too many times, aborting!\n"));
			ads_msgfree(ads, res);
			return ADS_ERROR(LDAP_NO_MEMORY);
		}
	}

	*strings = ads_pull_strings_range(ads, mem_ctx, res,
					 range_attr,
					 *strings,
					 &attrs[0],
					 num_strings,
					 more_values);

	ads_msgfree(ads, res);

	/* paranoia checks */
	if (*strings == NULL && *more_values) {
		DEBUG(0,("no strings found but more values???\n"));
		return ADS_ERROR(LDAP_NO_MEMORY);
	}
	if (*num_strings == 0 && *more_values) {
		DEBUG(0,("no strings found but more values???\n"));
		return ADS_ERROR(LDAP_NO_MEMORY);
	}

	return (*more_values) ? ADS_ERROR_NT(STATUS_MORE_ENTRIES) : ADS_ERROR(LDAP_SUCCESS);
}
Ejemplo n.º 18
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const struct dom_sid *sid,
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid = -1;
	int ret;
	char *ads_name;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;

	/* try netsamlogon cache first */

	if (winbindd_use_cache() && (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		return NT_STATUS_OK;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		return NT_STATUS_SERVER_DISABLED;
	}

	sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);

	ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
	TALLOC_FREE(sidstr);
	if (ret == -1) {
		return NT_STATUS_NO_MEMORY;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	SAFE_FREE(ldap_exp);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}
	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	/*
	 * We have to fetch the "name" attribute before doing the
	 * nss_get_info_cached call. nss_get_info_cached might destroy
	 * the ads struct, potentially invalidating the ldap message.
	 */
	ads_name = ads_pull_string(ads, mem_ctx, msg, "name");

	ads_msgfree(ads, msg);
	msg = NULL;

	status = nss_get_info_cached( domain, sid, mem_ctx,
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("nss_get_info_cached failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	if (info->full_name == NULL) {
		info->full_name = ads_name;
	} else {
		TALLOC_FREE(ads_name);
	}

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
	return NT_STATUS_OK;
}
Ejemplo n.º 19
0
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
			       TALLOC_CTX *mem_ctx,
			       uint32 *num_entries, 
			       struct wbint_userinfo **info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;

	*num_entries = 0;

	DEBUG(3,("ads: query_user_list\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("query_user_list: No users found\n"));
		goto done;
	}

	(*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
	if (!*info) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	i = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		const char *name;
		const char *gecos = NULL;
		const char *homedir = NULL;
		const char *shell = NULL;
		uint32 group;
		uint32 atype;
		DOM_SID user_sid;
		gid_t primary_gid = (gid_t)-1;

		if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
		    ds_atype_map(atype) != SID_NAME_USER) {
			DEBUG(1,("Not a user account? atype=0x%x\n", atype));
			continue;
		}

		name = ads_pull_username(ads, mem_ctx, msg);

		if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
			status = nss_get_info_cached( domain, &user_sid, mem_ctx, 
					       ads, msg, &homedir, &shell, &gecos,
					       &primary_gid );
		}

		if (gecos == NULL) {
			gecos = ads_pull_string(ads, mem_ctx, msg, "name");
		}

		if (!ads_pull_sid(ads, msg, "objectSid",
				  &(*info)[i].user_sid)) {
			DEBUG(1,("No sid for %s !?\n", name));
			continue;
		}
		if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
			DEBUG(1,("No primary group for %s !?\n", name));
			continue;
		}

		(*info)[i].acct_name = name;
		(*info)[i].full_name = gecos;
		(*info)[i].homedir = homedir;
		(*info)[i].shell = shell;
		(*info)[i].primary_gid = primary_gid;
		sid_compose(&(*info)[i].group_sid, &domain->sid, group);
		i++;
	}

	(*num_entries) = i;
	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));

done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}
Ejemplo n.º 20
0
static NTSTATUS add_primary_group_members(
	ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
	char ***all_members, size_t *num_all_members)
{
	char *filter;
	NTSTATUS status = NT_STATUS_NO_MEMORY;
	ADS_STATUS rc;
	const char *attrs[] = { "dn", NULL };
	LDAPMessage *res = NULL;
	LDAPMessage *msg;
	char **members;
	size_t num_members;
	ads_control args;

	filter = talloc_asprintf(
		mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
		(unsigned)rid);
	if (filter == NULL) {
		goto done;
	}

	args.control = ADS_EXTENDED_DN_OID;
	args.val = ADS_EXTENDED_DN_HEX_STRING;
	args.critical = True;

	rc = ads_do_search_all_args(ads, ads->config.bind_path,
				    LDAP_SCOPE_SUBTREE, filter, attrs, &args,
				    &res);

	if (!ADS_ERR_OK(rc)) {
		status = ads_ntstatus(rc);
		DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
		goto done;
	}
	if (res == NULL) {
		DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
		goto done;
	}

	num_members = ads_count_replies(ads, res);

	DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
		   (uintmax_t)num_members));

	if (num_members == 0) {
		status = NT_STATUS_OK;
		goto done;
	}

	members = talloc_realloc(mem_ctx, *all_members, char *,
				 *num_all_members + num_members);
	if (members == NULL) {
		DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
		goto done;
	}
	*all_members = members;

	for (msg = ads_first_entry(ads, res); msg != NULL;
	     msg = ads_next_entry(ads, msg)) {
		char *dn;

		dn = ads_get_dn(ads, members, msg);
		if (dn == NULL) {
			DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
			continue;
		}

		members[*num_all_members] = dn;
		*num_all_members += 1;
	}

	status = NT_STATUS_OK;
done:
	if (res != NULL) {
		ads_msgfree(ads, res);
	}
	TALLOC_FREE(filter);
	return status;
}
Ejemplo n.º 21
0
static WERROR nt_printer_dn_lookup(TALLOC_CTX *mem_ctx,
				   ADS_STRUCT *ads,
				   const char *printer,
				   char **pprinter_dn)
{
	char *printer_dn = NULL;
	char *srv_dn = NULL;
	char *srv_cn_0 = NULL;
	char *srv_cn_escaped = NULL;
	char *sharename_escaped = NULL;
	char *srv_dn_utf8 = NULL;
	char **srv_cn_utf8 = NULL;
	size_t converted_size;
	ADS_STATUS ads_status;
	LDAPMessage *res;
	WERROR result;
	bool ok;

	ads_status = ads_find_machine_acct(ads, &res, lp_netbios_name());
	if (!ADS_ERR_OK(ads_status)) {
		DEBUG(2, ("Failed to find machine account for %s\n",
			  lp_netbios_name()));
		result = WERR_NOT_FOUND;
		goto err_out;
	}

	/*
	 * We use ldap_get_dn here as we need the answer in utf8 to call
	 * ldap_explode_dn(). JRA.
	 */
	srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
	ads_msgfree(ads, res);
	if (srv_dn_utf8 == NULL) {
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
	if (srv_cn_utf8 == NULL) {
		ldap_memfree(srv_dn_utf8);
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	/* Now convert to CH_UNIX. */
	ok = pull_utf8_talloc(mem_ctx, &srv_dn, srv_dn_utf8, &converted_size);
	ldap_memfree(srv_dn_utf8);
	if (!ok) {
		ldap_memfree(srv_cn_utf8);
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	ok = pull_utf8_talloc(mem_ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size);
	ldap_memfree(srv_cn_utf8);
	if (!ok) {
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
	if (srv_cn_escaped == NULL) {
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	sharename_escaped = escape_rdn_val_string_alloc(printer);
	if (sharename_escaped == NULL) {
		result = WERR_SERVER_UNAVAILABLE;
		goto err_out;
	}

	printer_dn = talloc_asprintf(mem_ctx,
				     "cn=%s-%s,%s",
				     srv_cn_escaped,
				     sharename_escaped,
				     srv_dn);
	if (printer_dn == NULL) {
		result = WERR_NOMEM;
		goto err_out;
	}

	*pprinter_dn = printer_dn;

	result = WERR_OK;
err_out:
	SAFE_FREE(sharename_escaped);
	SAFE_FREE(srv_cn_escaped);
	TALLOC_FREE(srv_cn_0);
	TALLOC_FREE(srv_dn);
	return result;
}
Ejemplo n.º 22
0
/* convert a single name to a sid in a domain */
NTSTATUS ads_name_to_sid(ADS_STRUCT *ads,
			 const char *name,
			 DOM_SID *sid,
			 enum SID_NAME_USE *type)
{
	const char *attrs[] = {"objectSid", "sAMAccountType", NULL};
	int count;
	ADS_STATUS rc;
	void *res = NULL;
	char *ldap_exp;
	uint32 t;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	char *escaped_name = escape_ldap_string_alloc(name);
	char *escaped_realm = escape_ldap_string_alloc(ads->config.realm);

	if (!escaped_name || !escaped_realm) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (asprintf(&ldap_exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))", 
		     escaped_name, escaped_name, escaped_realm) == -1) {
		DEBUG(1,("ads_name_to_sid: asprintf failed!\n"));
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	rc = ads_search_retry(ads, &res, ldap_exp, attrs);
	free(ldap_exp);
	if (!ADS_ERR_OK(rc)) {
		DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count != 1) {
		DEBUG(1,("name_to_sid: %s not found\n", name));
		goto done;
	}

	if (!ads_pull_sid(ads, res, "objectSid", sid)) {
		DEBUG(1,("No sid for %s !?\n", name));
		goto done;
	}

	if (!ads_pull_uint32(ads, res, "sAMAccountType", &t)) {
		DEBUG(1,("No sAMAccountType for %s !?\n", name));
		goto done;
	}

	*type = ads_atype_map(t);

	status = NT_STATUS_OK;

	DEBUG(3,("ads name_to_sid mapped %s\n", name));

done:
	if (res) ads_msgfree(ads, res);

	SAFE_FREE(escaped_name);
	SAFE_FREE(escaped_realm);

	return status;
}
Ejemplo n.º 23
0
ADS_STATUS ads_sid_to_dn(ADS_STRUCT *ads,
			 TALLOC_CTX *mem_ctx,
			 const DOM_SID *sid,
			 char **dn)
{
	ADS_STATUS rc;
	LDAPMessage *msg = NULL;
	LDAPMessage *entry = NULL;
	char *ldap_exp;
	char *sidstr = NULL;
	int count;
	char *dn2 = NULL;

	const char *attr[] = {
		"dn",
		NULL
	};

	if (!(sidstr = sid_binstring(sid))) {
		DEBUG(1,("ads_sid_to_dn: sid_binstring failed!\n"));
		rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto done;
	}

	if(!(ldap_exp = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr))) {
		DEBUG(1,("ads_sid_to_dn: talloc_asprintf failed!\n"));
		rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto done;
	}

	rc = ads_search_retry(ads, (void **)&msg, ldap_exp, attr);

	if (!ADS_ERR_OK(rc)) {
		DEBUG(1,("ads_sid_to_dn ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	if ((count = ads_count_replies(ads, msg)) != 1) {
		fstring sid_string;
		DEBUG(1,("ads_sid_to_dn (sid=%s): Not found (count=%d)\n", 
			 sid_to_string(sid_string, sid), count));
		rc = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
		goto done;
	}

	entry = ads_first_entry(ads, msg);

	dn2 = ads_get_dn(ads, entry);

	if (!dn2) {
		rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto done;
	}

	*dn = talloc_strdup(mem_ctx, dn2);

	if (!*dn) {
		ads_memfree(ads, dn2);
		rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto done;
	}

	rc = ADS_ERROR_NT(NT_STATUS_OK);

	DEBUG(3,("ads sid_to_dn mapped %s\n", dn2));

	SAFE_FREE(dn2);
done:
	if (msg) ads_msgfree(ads, msg);
	if (dn2) ads_memfree(ads, dn2);

	SAFE_FREE(sidstr);

	return rc;
}
Ejemplo n.º 24
0
/*
  a wrapper around ldap_search_s that retries depending on the error code
  this is supposed to catch dropped connections and auto-reconnect
*/
static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind_path, int scope, 
					       const char *expr,
					       const char **attrs, void *args,
					       LDAPMessage **res)
{
	ADS_STATUS status = ADS_SUCCESS;
	int count = 3;
	char *bp;

	*res = NULL;

	if (!ads->ldap.ld &&
	    time_mono(NULL) - ads->ldap.last_attempt < ADS_RECONNECT_TIME) {
		return ADS_ERROR(LDAP_SERVER_DOWN);
	}

	bp = SMB_STRDUP(bind_path);

	if (!bp) {
		return ADS_ERROR(LDAP_NO_MEMORY);
	}

	*res = NULL;

	/* when binding anonymously, we cannot use the paged search LDAP
	 * control - Guenther */

	if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
		status = ads_do_search(ads, bp, scope, expr, attrs, res);
	} else {
		status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res);
	}
	if (ADS_ERR_OK(status)) {
               DEBUG(5,("Search for %s in <%s> gave %d replies\n",
                        expr, bp, ads_count_replies(ads, *res)));
		SAFE_FREE(bp);
		return status;
	}

	while (--count) {

		if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) && ads->config.ldap_page_size >= 250) {
			int new_page_size = (ads->config.ldap_page_size / 2);
			DEBUG(1, ("Reducing LDAP page size from %d to %d due to IO_TIMEOUT\n",
				  ads->config.ldap_page_size, new_page_size));
			ads->config.ldap_page_size = new_page_size;
		}

		if (*res) 
			ads_msgfree(ads, *res);
		*res = NULL;

		DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", 
			 ads->config.realm, ads_errstr(status)));

		ads_disconnect(ads);
		status = ads_connect(ads);

		if (!ADS_ERR_OK(status)) {
			DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
				 ads_errstr(status)));
			ads_destroy(&ads);
			SAFE_FREE(bp);
			return status;
		}

		*res = NULL;

		/* when binding anonymously, we cannot use the paged search LDAP
		 * control - Guenther */

		if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
			status = ads_do_search(ads, bp, scope, expr, attrs, res);
		} else {
			status = ads_do_search_all_args(ads, bp, scope, expr, attrs, args, res);
		}

		if (ADS_ERR_OK(status)) {
			DEBUG(5,("Search for filter: %s, base: %s gave %d replies\n",
				 expr, bp, ads_count_replies(ads, *res)));
			SAFE_FREE(bp);
			return status;
		}
	}
        SAFE_FREE(bp);

	if (!ADS_ERR_OK(status)) {
		DEBUG(1,("ads reopen failed after error %s\n", 
			 ads_errstr(status)));
	}
	return status;
}
Ejemplo n.º 25
0
/* Lookup groups a user is a member of - alternate method, for when
   tokenGroups are not available. */
static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
					 TALLOC_CTX *mem_ctx,
					 const char *user_dn, 
					 struct dom_sid *primary_group,
					 uint32_t *p_num_groups, struct dom_sid **user_sids)
{
	ADS_STATUS rc;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	int count;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	ADS_STRUCT *ads;
	const char *group_attrs[] = {"objectSid", NULL};
	char *escaped_dn;
	uint32_t num_groups = 0;

	DEBUG(3,("ads: lookup_usergroups_member\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ldap_exp = talloc_asprintf(mem_ctx,
		"(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
		escaped_dn,
		ADS_LDAP_MATCHING_RULE_BIT_AND,
		GROUP_TYPE_SECURITY_ENABLED);
	if (!ldap_exp) {
		DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
		TALLOC_FREE(escaped_dn);
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	TALLOC_FREE(escaped_dn);

	rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);

	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	count = ads_count_replies(ads, res);

	*user_sids = NULL;
	num_groups = 0;

	/* always add the primary group to the sid array */
	status = add_sid_to_array(mem_ctx, primary_group, user_sids,
				  &num_groups);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if (count > 0) {
		for (msg = ads_first_entry(ads, res); msg;
		     msg = ads_next_entry(ads, msg)) {
			struct dom_sid group_sid;

			if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
				DEBUG(1,("No sid for this group ?!?\n"));
				continue;
			}

			/* ignore Builtin groups from ADS - Guenther */
			if (sid_check_is_in_builtin(&group_sid)) {
				continue;
			}

			status = add_sid_to_array(mem_ctx, &group_sid,
						  user_sids, &num_groups);
			if (!NT_STATUS_IS_OK(status)) {
				goto done;
			}
		}

	}

	*p_num_groups = num_groups;
	status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;

	DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}
Ejemplo n.º 26
0
static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
				     ADS_STRUCT *ads,
				     struct spoolss_PrinterInfo2 *pinfo2)
{
	ADS_STATUS ads_rc;
	LDAPMessage *res;
	char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
	char *srv_dn_utf8, **srv_cn_utf8;
	TALLOC_CTX *ctx;
	ADS_MODLIST mods;
	const char *attrs[] = {"objectGUID", NULL};
	struct GUID guid;
	WERROR win_rc = WERR_OK;
	size_t converted_size;
	const char *printer = pinfo2->sharename;

	/* build the ads mods */
	ctx = talloc_init("nt_printer_publish_ads");
	if (ctx == NULL) {
		return WERR_NOMEM;
	}

	DEBUG(5, ("publishing printer %s\n", printer));

	/* figure out where to publish */
	ads_find_machine_acct(ads, &res, lp_netbios_name());

	/* We use ldap_get_dn here as we need the answer
	 * in utf8 to call ldap_explode_dn(). JRA. */

	srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
	if (!srv_dn_utf8) {
		TALLOC_FREE(ctx);
		return WERR_SERVER_UNAVAILABLE;
	}
	ads_msgfree(ads, res);
	srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
	if (!srv_cn_utf8) {
		TALLOC_FREE(ctx);
		ldap_memfree(srv_dn_utf8);
		return WERR_SERVER_UNAVAILABLE;
	}
	/* Now convert to CH_UNIX. */
	if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
		TALLOC_FREE(ctx);
		ldap_memfree(srv_dn_utf8);
		ldap_memfree(srv_cn_utf8);
		return WERR_SERVER_UNAVAILABLE;
	}
	if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
		TALLOC_FREE(ctx);
		ldap_memfree(srv_dn_utf8);
		ldap_memfree(srv_cn_utf8);
		TALLOC_FREE(srv_dn);
		return WERR_SERVER_UNAVAILABLE;
	}

	ldap_memfree(srv_dn_utf8);
	ldap_memfree(srv_cn_utf8);

	srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
	if (!srv_cn_escaped) {
		TALLOC_FREE(ctx);
		return WERR_SERVER_UNAVAILABLE;
	}
	sharename_escaped = escape_rdn_val_string_alloc(printer);
	if (!sharename_escaped) {
		SAFE_FREE(srv_cn_escaped);
		TALLOC_FREE(ctx);
		return WERR_SERVER_UNAVAILABLE;
	}

	prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);

	SAFE_FREE(srv_cn_escaped);
	SAFE_FREE(sharename_escaped);

	mods = ads_init_mods(ctx);

	if (mods == NULL) {
		SAFE_FREE(prt_dn);
		TALLOC_FREE(ctx);
		return WERR_NOMEM;
	}

	ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);

	/* publish it */
	ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
	if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
		int i;
		for (i=0; mods[i] != 0; i++)
			;
		mods[i] = (LDAPMod *)-1;
		ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
	}

	if (!ADS_ERR_OK(ads_rc)) {
		DEBUG(3, ("error publishing %s: %s\n",
			  printer, ads_errstr(ads_rc)));
	}

	/* retreive the guid and store it locally */
	if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
		bool guid_ok;
		ZERO_STRUCT(guid);
		guid_ok = ads_pull_guid(ads, res, &guid);
		ads_msgfree(ads, res);
		if (guid_ok) {
			store_printer_guid(msg_ctx, printer, guid);
		}
	}
	TALLOC_FREE(ctx);

	return win_rc;
}
Ejemplo n.º 27
0
/*
  join a domain using ADS
 */
int net_ads_join(int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS rc;
	char *password;
	char *machine_account = NULL;
	char *tmp_password;
	const char *org_unit = "Computers";
	char *dn;
	void *res;
	DOM_SID dom_sid;
	char *ou_str;
	uint32 sec_channel_type = SEC_CHAN_WKSTA;
	uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT;
	const char *short_domain_name = NULL;
	TALLOC_CTX *ctx = NULL;

	if (argc > 0) {
		org_unit = argv[0];
	}

	if (!secrets_init()) {
		DEBUG(1,("Failed to initialise secrets database\n"));
		return -1;
	}

	tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
	password = strdup(tmp_password);

	if (!(ads = ads_startup())) {
		return -1;
	}

	if (!*lp_realm()) {
		d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
		ads_destroy(&ads);
		return -1;
	}

	if (strcmp(ads->config.realm, lp_realm()) != 0) {
		d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match.  Aborting join\n", ads->config.realm, lp_realm());
		ads_destroy(&ads);
		return -1;
	}

	ou_str = ads_ou_string(org_unit);
	asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
	free(ou_str);

	rc = ads_search_dn(ads, &res, dn, NULL);
	ads_msgfree(ads, res);

	if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
		d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", 
			 org_unit, dn);
		ads_destroy(&ads);
		return -1;
	}
	free(dn);

	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_join_realm: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}	

	rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_join_realm: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}

	rc = ads_domain_sid(ads, &dom_sid);
	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_domain_sid: %s\n", ads_errstr(rc));	
		ads_destroy(&ads);
		return -1;
	}

	if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
		d_printf("asprintf failed\n");
		ads_destroy(&ads);
		return -1;
	}

	rc = ads_set_machine_password(ads, machine_account, password);
	if (!ADS_ERR_OK(rc)) {
		d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
		ads_destroy(&ads);
		return -1;
	}
	
	/* make sure we get the right workgroup */
	
	if ( !(ctx = talloc_init("net ads join")) ) {
		d_printf("talloc_init() failed!\n");
		ads_destroy(&ads);
		return -1;
	}
	
	rc = ads_workgroup_name(ads, ctx, &short_domain_name);
	if ( ADS_ERR_OK(rc) ) {
		if ( !strequal(lp_workgroup(), short_domain_name) ) {
			d_printf("The workgroup in smb.conf does not match the short\n");
			d_printf("domain name obtained from the server.\n");
			d_printf("Using the name [%s] from the server.\n", short_domain_name);
			d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
		}
	} else {
		short_domain_name = lp_workgroup();
	}
	
	d_printf("Using short domain name -- %s\n", short_domain_name);
	
	/*  HACK ALRET!  Store the sid and password under bother the lp_workgroup() 
	    value from smb.conf and the string returned from the server.  The former is
	    neede to bootstrap winbindd's first connection to the DC to get the real 
	    short domain name   --jerry */
	    
	if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
		DEBUG(1,("Failed to save domain sid\n"));
		ads_destroy(&ads);
		return -1;
	}

	if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
		DEBUG(1,("Failed to save machine password\n"));
		ads_destroy(&ads);
		return -1;
	}

	if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
		DEBUG(1,("Failed to save domain sid\n"));
		ads_destroy(&ads);
		return -1;
	}

	if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
		DEBUG(1,("Failed to save machine password\n"));
		ads_destroy(&ads);
		return -1;
	}
	
	/* Now build the keytab, using the same ADS connection */
	if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
		DEBUG(1,("Error creating host keytab!\n"));
	}

	d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);

	SAFE_FREE(password);
	SAFE_FREE(machine_account);
	if ( ctx ) {
		talloc_destroy(ctx);
	}
	ads_destroy(&ads);
	return 0;
}
Ejemplo n.º 28
0
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
			       TALLOC_CTX *mem_ctx,
			       uint32 *num_entries, 
			       struct wbint_userinfo **pinfo)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;

	*num_entries = 0;

	DEBUG(3,("ads: query_user_list\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("query_user_list: No users found\n"));
		goto done;
	}

	(*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
	if (!*pinfo) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	count = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		struct wbint_userinfo *info = &((*pinfo)[count]);
		uint32 group;
		uint32 atype;

		if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
		    ds_atype_map(atype) != SID_NAME_USER) {
			DEBUG(1,("Not a user account? atype=0x%x\n", atype));
			continue;
		}

		info->acct_name = ads_pull_username(ads, mem_ctx, msg);
		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
		info->homedir = NULL;
		info->shell = NULL;
		info->primary_gid = (gid_t)-1;

		if (!ads_pull_sid(ads, msg, "objectSid",
				  &info->user_sid)) {
			DEBUG(1, ("No sid for %s !?\n", info->acct_name));
			continue;
		}

		if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
			DEBUG(1, ("No primary group for %s !?\n",
				  info->acct_name));
			continue;
		}
		sid_compose(&info->group_sid, &domain->sid, group);

		count += 1;
	}

	(*num_entries) = count;
	ads_msgfree(ads, res);

	for (i=0; i<count; i++) {
		struct wbint_userinfo *info = &((*pinfo)[i]);
		const char *gecos = NULL;
		gid_t primary_gid = (gid_t)-1;

		status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
					     &info->homedir, &info->shell,
					     &gecos, &primary_gid);
		if (!NT_STATUS_IS_OK(status)) {
			/*
			 * Deliberately ignore this error, there might be more
			 * users to fill
			 */
			continue;
		}

		if (gecos != NULL) {
			info->full_name = gecos;
		}
		info->primary_gid = primary_gid;
	}

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));

done:
	return status;
}
Ejemplo n.º 29
0
/* list all domain groups */
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
				TALLOC_CTX *mem_ctx,
				uint32 *num_entries, 
				struct wb_acct_info **info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = {"userPrincipalName", "sAMAccountName",
			       "name", "objectSid", NULL};
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	const char *filter;
	bool enum_dom_local_groups = False;

	*num_entries = 0;

	DEBUG(3,("ads: enum_dom_groups\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	/* only grab domain local groups for our domain */
	if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
		enum_dom_local_groups = True;
	}

	/* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
	 * rollup-fixes:
	 *
	 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
	 * default value, it MUST be absent. In case of extensible matching the
	 * "dnattr" boolean defaults to FALSE and so it must be only be present
	 * when set to TRUE. 
	 *
	 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
	 * filter using bitwise matching rule then the buggy AD fails to decode
	 * the extensible match. As a workaround set it to TRUE and thereby add
	 * the dnAttributes "dn" field to cope with those older AD versions.
	 * It should not harm and won't put any additional load on the AD since
	 * none of the dn components have a bitmask-attribute.
	 *
	 * Thanks to Ralf Haferkamp for input and testing - Guenther */

	filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
				 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
				 ADS_LDAP_MATCHING_RULE_BIT_AND, 
				 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);

	if (filter == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, filter, attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("enum_dom_groups: No groups found\n"));
		goto done;
	}

	(*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
	if (!*info) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	i = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		char *name, *gecos;
		struct dom_sid sid;
		uint32 rid;

		name = ads_pull_username(ads, mem_ctx, msg);
		gecos = ads_pull_string(ads, mem_ctx, msg, "name");
		if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
			DEBUG(1,("No sid for %s !?\n", name));
			continue;
		}

		if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
			DEBUG(1,("No rid for %s !?\n", name));
			continue;
		}

		fstrcpy((*info)[i].acct_name, name);
		fstrcpy((*info)[i].acct_desc, gecos);
		(*info)[i].rid = rid;
		i++;
	}

	(*num_entries) = i;

	status = NT_STATUS_OK;

	DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));

done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}
Ejemplo n.º 30
0
static int net_ads_gpo_list(struct net_context *c, int argc, const char **argv)
{
	ADS_STRUCT *ads;
	ADS_STATUS status;
	LDAPMessage *res = NULL;
	TALLOC_CTX *mem_ctx;
	const char *dn = NULL;
	uint32 uac = 0;
	uint32 flags = 0;
	struct GROUP_POLICY_OBJECT *gpo_list;
	struct nt_user_token *token = NULL;

	if (argc < 1 || c->display_usage) {
		d_printf("Usage:\n"
			 "net ads gpo list <username|machinename>\n"
			 "  Lists all GPOs for machine/user\n"
			 "    username\tUser to list GPOs for\n"
			 "    machinename\tMachine to list GPOs for\n");
		return -1;
	}

	mem_ctx = talloc_init("net_ads_gpo_list");
	if (mem_ctx == NULL) {
		goto out;
	}

	status = ads_startup(c, false, &ads);
	if (!ADS_ERR_OK(status)) {
		goto out;
	}

	status = ads_find_samaccount(ads, mem_ctx, argv[0], &uac, &dn);
	if (!ADS_ERR_OK(status)) {
		goto out;
	}

	if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
		flags |= GPO_LIST_FLAG_MACHINE;
	}

	d_printf("%s: '%s' has dn: '%s'\n",
		(uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user",
		argv[0], dn);

	if (uac & UF_WORKSTATION_TRUST_ACCOUNT) {
		status = gp_get_machine_token(ads, mem_ctx, dn, &token);
	} else {
		status = ads_get_sid_token(ads, mem_ctx, dn, &token);
	}

	if (!ADS_ERR_OK(status)) {
		goto out;
	}

	status = ads_get_gpo_list(ads, mem_ctx, dn, flags, token, &gpo_list);
	if (!ADS_ERR_OK(status)) {
		goto out;
	}

	dump_gpo_list(ads, mem_ctx, gpo_list, 0);

out:
	ads_msgfree(ads, res);

	talloc_destroy(mem_ctx);
	ads_destroy(&ads);

	return 0;
}