1/* 2 Samba CIFS implementation 3 ADS convenience functions for GPO 4 5 Copyright (C) 2001 Andrew Tridgell (from samba3 ads.c) 6 Copyright (C) 2001 Remus Koos (from samba3 ads.c) 7 Copyright (C) 2001 Andrew Bartlett (from samba3 ads.c) 8 Copyright (C) 2008 Jelmer Vernooij, jelmer@samba.org 9 Copyright (C) 2008 Wilco Baan Hofman, wilco@baanhofman.nl 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "includes.h" 26#include "libnet/libnet.h" 27#include "librpc/gen_ndr/ndr_security.h" 28#include "libgpo/ads_convenience.h" 29#include "param/param.h" 30#include "libcli/libcli.h" 31#include "ldb_wrap.h" 32 33static ADS_STATUS ads_connect(ADS_STRUCT *ads); 34 35WERROR ads_startup (struct libnet_context *netctx, ADS_STRUCT **ads) 36{ 37 *ads = talloc(netctx, ADS_STRUCT); 38 (*ads)->netctx = netctx; 39 40 ads_connect(*ads); 41 42 return WERR_OK; 43} 44 45static ADS_STATUS ads_connect(ADS_STRUCT *ads) 46{ 47 struct libnet_LookupDCs *io; 48 char *url; 49 50 io = talloc_zero(ads, struct libnet_LookupDCs); 51 52 /* We are looking for the PDC of the active domain. */ 53 io->in.name_type = NBT_NAME_PDC; 54 io->in.domain_name = lp_workgroup(ads->netctx->lp_ctx); 55 libnet_LookupDCs(ads->netctx, ads, io); 56 57 url = talloc_asprintf(ads, "ldap://%s", io->out.dcs[0].name); 58 ads->ldbctx = ldb_wrap_connect(ads, ads->netctx->event_ctx, ads->netctx->lp_ctx, 59 url, NULL, ads->netctx->cred, 0, NULL); 60 if (ads->ldbctx == NULL) { 61 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 62 } 63 64 return ADS_ERROR_NT(NT_STATUS_OK); 65} 66 67ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res, 68 const char *dn, const char **attrs) 69{ 70 ADS_STATUS status; 71 72 status.err.rc = ldb_search(ads->ldbctx, ads, res, 73 ldb_dn_new(ads, ads->ldbctx, dn), 74 LDB_SCOPE_BASE, 75 attrs, 76 "(objectclass=*)"); 77 78 status.error_type = ENUM_ADS_ERROR_LDAP; 79 return status; 80} 81 82const char * ads_get_dn(ADS_STRUCT *ads, LDAPMessage *res) 83{ 84 return ldb_dn_get_linearized(res->msgs[0]->dn); 85} 86 87bool ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *ctx, LDAPMessage *res, const char *field, struct security_descriptor **sd) 88{ 89 const struct ldb_val *val; 90 enum ndr_err_code ndr_err; 91 92 val = ldb_msg_find_ldb_val(res->msgs[0], field); 93 94 *sd = talloc(ctx, struct security_descriptor); 95 if (*sd == NULL) { 96 return -1; 97 } 98 /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */ 99 ndr_err = ndr_pull_struct_blob(val, *sd, NULL, *sd, 100 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); 101 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 102 talloc_free(*sd); 103 return -1; 104 } 105 return 0; 106} 107 108ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res, uint32_t sd_flags, 109 const char *dn, const char **attrs) 110{ 111 return ads_do_search_all_sd_flags(ads, dn, LDB_SCOPE_BASE, "(objectclass=*)", attrs, sd_flags, res); 112} 113 114ADS_STATUS ads_do_search_all_sd_flags (ADS_STRUCT *ads, const char *dn, int scope, 115 const char *filter, const char **attrs, 116 uint32_t sd_flags, LDAPMessage **res) 117{ 118 int rv; 119 struct ldb_request *req; 120 struct ldb_control **controls; 121 struct ldb_parse_tree *tree; 122 struct ldb_dn *ldb_dn; 123 124 controls = talloc_zero_array(ads, struct ldb_control *, 2); 125 controls[0] = talloc(ads, struct ldb_control); 126 controls[0]->oid = LDB_CONTROL_SD_FLAGS_OID; 127 controls[0]->data = &sd_flags; 128 controls[0]->critical = 1; 129 130 tree = ldb_parse_tree(ads, filter); 131 132 ldb_dn = ldb_dn_new(ads, ads->ldbctx, dn); 133 134 rv = ldb_build_search_req_ex(&req, ads->ldbctx, (TALLOC_CTX *)res, ldb_dn, scope, tree, attrs, controls, 135 res, ldb_search_default_callback, NULL); 136 if (rv != LDB_SUCCESS) { 137 talloc_free(*res); 138 talloc_free(req); 139 talloc_free(tree); 140 return ADS_ERROR(rv); 141 } 142 rv = ldb_request(ads->ldbctx, req); 143 if (rv == LDB_SUCCESS) { 144 rv = ldb_wait(req->handle, LDB_WAIT_ALL); 145 } 146 147 talloc_free(req); 148 talloc_free(tree); 149 return ADS_ERROR(rv); 150 151} 152 153const char * ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *ctx, LDAPMessage *res, const char *field) 154{ 155 return ldb_msg_find_attr_as_string(res->msgs[0], field, NULL); 156} 157 158bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *res, const char *field, uint32_t *ret) 159{ 160 if (ldb_msg_find_element(res->msgs[0], field) == NULL) { 161 return false; 162 } 163 *ret = ldb_msg_find_attr_as_uint(res->msgs[0], field, 0); 164 return true; 165} 166 167 168int ads_count_replies(ADS_STRUCT *ads, LDAPMessage *res) 169{ 170 return res->count; 171} 172 173ADS_STATUS ads_msgfree(ADS_STRUCT *ads, LDAPMessage *res) 174{ 175 talloc_free(res); 176 return ADS_ERROR_NT(NT_STATUS_OK); 177} 178 179/* 180 do a rough conversion between ads error codes and NT status codes 181 we'll need to fill this in more 182*/ 183NTSTATUS ads_ntstatus(ADS_STATUS status) 184{ 185 switch (status.error_type) { 186 case ENUM_ADS_ERROR_NT: 187 return status.err.nt_status; 188 case ENUM_ADS_ERROR_SYSTEM: 189 return map_nt_error_from_unix(status.err.rc); 190 case ENUM_ADS_ERROR_LDAP: 191 if (status.err.rc == LDB_SUCCESS) { 192 return NT_STATUS_OK; 193 } 194 return NT_STATUS_UNSUCCESSFUL; 195 default: 196 break; 197 } 198 199 if (ADS_ERR_OK(status)) { 200 return NT_STATUS_OK; 201 } 202 return NT_STATUS_UNSUCCESSFUL; 203} 204 205/* 206 return a string for an error from an ads routine 207*/ 208const char *ads_errstr(ADS_STATUS status) 209{ 210 switch (status.error_type) { 211 case ENUM_ADS_ERROR_SYSTEM: 212 return strerror(status.err.rc); 213 case ENUM_ADS_ERROR_LDAP: 214 return ldb_strerror(status.err.rc); 215 case ENUM_ADS_ERROR_NT: 216 return get_friendly_nt_error_msg(ads_ntstatus(status)); 217 default: 218 return "Unknown ADS error type!? (not compiled in?)"; 219 } 220} 221 222ADS_STATUS ads_build_ldap_error(int ldb_error) 223{ 224 ADS_STATUS ret; 225 ret.err.rc = ldb_error; 226 ret.error_type = ENUM_ADS_ERROR_LDAP; 227 return ret; 228} 229 230ADS_STATUS ads_build_nt_error(NTSTATUS nt_status) 231{ 232 ADS_STATUS ret; 233 ret.err.nt_status = nt_status; 234 ret.error_type = ENUM_ADS_ERROR_NT; 235 return ret; 236} 237 238 239bool nt_token_check_sid( const struct dom_sid *sid, const NT_USER_TOKEN *token) 240{ 241 int i; 242 243 if (!sid || !token) { 244 return false; 245 } 246 247 if (dom_sid_equal(sid, token->user_sid)) { 248 return true; 249 } 250 if (dom_sid_equal(sid, token->group_sid)) { 251 return true; 252 } 253 for (i = 0; i < token->num_sids; i++) { 254 if (dom_sid_equal(sid, token->sids[i])) { 255 return true; 256 } 257 } 258 259 return false; 260} 261const char *ads_get_ldap_server_name(ADS_STRUCT *ads) { 262 return ads->ldap_server_name; 263} 264 265 266/* 267 FIXME 268 Stub write functions, these do not do anything, though they should. -- Wilco 269*/ 270 271ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx) 272{ 273 return NULL; 274} 275 276ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods, const char *name, const char *val) 277{ 278 return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); 279} 280 281ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods) 282{ 283 return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); 284} 285