1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind authentication mechnism 5 6 Copyright (C) Tim Potter 2000 7 Copyright (C) Andrew Bartlett 2001 - 2002 8 Copyright (C) Stefan Metzmacher 2005 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <http://www.gnu.org/licenses/>. 22*/ 23 24#include "includes.h" 25#include "auth/auth.h" 26#include "auth/ntlm/auth_proto.h" 27#include "auth/auth_sam_reply.h" 28#include "nsswitch/winbind_client.h" 29#include "librpc/gen_ndr/ndr_netlogon.h" 30#include "librpc/gen_ndr/ndr_winbind.h" 31#include "lib/messaging/irpc.h" 32#include "param/param.h" 33#include "nsswitch/libwbclient/wbclient.h" 34#include "libcli/security/dom_sid.h" 35 36static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct winbindd_response *response, struct netr_SamInfo3 *info3) 37{ 38 size_t len = response->length - sizeof(struct winbindd_response); 39 if (len > 4) { 40 enum ndr_err_code ndr_err; 41 DATA_BLOB blob; 42 blob.length = len - 4; 43 blob.data = (uint8_t *)(((char *)response->extra_data.data) + 4); 44 45 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, 46 iconv_convenience, info3, 47 (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3); 48 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 49 return ndr_map_error2ntstatus(ndr_err); 50 } 51 52 return NT_STATUS_OK; 53 } else { 54 DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); 55 return NT_STATUS_UNSUCCESSFUL; 56 } 57} 58 59static NTSTATUS get_info3_from_wbcAuthUserInfo(TALLOC_CTX *mem_ctx, 60 struct smb_iconv_convenience *ic, 61 struct wbcAuthUserInfo *info, 62 struct netr_SamInfo3 *info3) 63{ 64 int i, j; 65 struct samr_RidWithAttribute *rids = NULL; 66 67 info3->base.last_logon = info->logon_time; 68 info3->base.last_logoff = info->logoff_time; 69 info3->base.acct_expiry = info->kickoff_time; 70 info3->base.last_password_change = info->pass_last_set_time; 71 info3->base.allow_password_change = info->pass_can_change_time; 72 info3->base.force_password_change = info->pass_must_change_time; 73 74 info3->base.account_name.string = talloc_strdup(mem_ctx, 75 info->account_name); 76 info3->base.full_name.string = talloc_strdup(mem_ctx, 77 info->full_name); 78 info3->base.logon_script.string = talloc_strdup(mem_ctx, 79 info->logon_script); 80 info3->base.profile_path.string = talloc_strdup(mem_ctx, 81 info->profile_path); 82 info3->base.home_directory.string = talloc_strdup(mem_ctx, 83 info->home_directory); 84 info3->base.home_drive.string = talloc_strdup(mem_ctx, 85 info->home_drive); 86 info3->base.logon_server.string = talloc_strdup(mem_ctx, 87 info->logon_server); 88 info3->base.domain.string = talloc_strdup(mem_ctx, 89 info->domain_name); 90 91 info3->base.logon_count = info->logon_count; 92 info3->base.bad_password_count = info->bad_password_count; 93 info3->base.user_flags = info->user_flags; 94 memcpy(info3->base.key.key, info->user_session_key, 95 sizeof(info3->base.key.key)); 96 memcpy(info3->base.LMSessKey.key, info->lm_session_key, 97 sizeof(info3->base.LMSessKey.key)); 98 info3->base.acct_flags = info->acct_flags; 99 memset(info3->base.unknown, 0, sizeof(info3->base.unknown)); 100 101 if (info->num_sids < 2) { 102 return NT_STATUS_INVALID_PARAMETER; 103 } 104 105 dom_sid_split_rid(mem_ctx, (struct dom_sid2 *) &info->sids[0].sid, 106 &info3->base.domain_sid, 107 &info3->base.rid); 108 dom_sid_split_rid(mem_ctx, (struct dom_sid2 *) &info->sids[1].sid, NULL, 109 &info3->base.primary_gid); 110 111 /* We already handled the first two, now take care of the rest */ 112 info3->base.groups.count = info->num_sids - 2; 113 114 rids = talloc_array(mem_ctx, struct samr_RidWithAttribute, 115 info3->base.groups.count); 116 NT_STATUS_HAVE_NO_MEMORY(rids); 117 118 for (i = 2, j = 0; i < info->num_sids; ++i, ++j) { 119 rids[j].attributes = info->sids[i].attributes; 120 dom_sid_split_rid(mem_ctx, 121 (struct dom_sid2 *) &info->sids[i].sid, 122 NULL, &rids[j].rid); 123 } 124 info3->base.groups.rids = rids; 125 126 return NT_STATUS_OK; 127} 128 129 130static NTSTATUS winbind_want_check(struct auth_method_context *ctx, 131 TALLOC_CTX *mem_ctx, 132 const struct auth_usersupplied_info *user_info) 133{ 134 if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { 135 return NT_STATUS_NOT_IMPLEMENTED; 136 } 137 138 /* TODO: maybe limit the user scope to remote users only */ 139 return NT_STATUS_OK; 140} 141 142/* 143 Authenticate a user with a challenge/response 144 using the samba3 winbind protocol 145*/ 146static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, 147 TALLOC_CTX *mem_ctx, 148 const struct auth_usersupplied_info *user_info, 149 struct auth_serversupplied_info **server_info) 150{ 151 struct winbindd_request request; 152 struct winbindd_response response; 153 NSS_STATUS result; 154 NTSTATUS nt_status; 155 struct netr_SamInfo3 info3; 156 157 /* Send off request */ 158 const struct auth_usersupplied_info *user_info_temp; 159 nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, 160 AUTH_PASSWORD_RESPONSE, 161 user_info, &user_info_temp); 162 if (!NT_STATUS_IS_OK(nt_status)) { 163 return nt_status; 164 } 165 user_info = user_info_temp; 166 167 ZERO_STRUCT(request); 168 ZERO_STRUCT(response); 169 request.flags = WBFLAG_PAM_INFO3_NDR; 170 171 request.data.auth_crap.logon_parameters = user_info->logon_parameters; 172 173 safe_strcpy(request.data.auth_crap.user, 174 user_info->client.account_name, sizeof(fstring)); 175 safe_strcpy(request.data.auth_crap.domain, 176 user_info->client.domain_name, sizeof(fstring)); 177 safe_strcpy(request.data.auth_crap.workstation, 178 user_info->workstation_name, sizeof(fstring)); 179 180 memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); 181 182 request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, 183 sizeof(request.data.auth_crap.lm_resp)); 184 request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, 185 sizeof(request.data.auth_crap.nt_resp)); 186 187 memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, 188 request.data.auth_crap.lm_resp_len); 189 memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, 190 request.data.auth_crap.nt_resp_len); 191 192 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); 193 194 nt_status = NT_STATUS(response.data.auth.nt_status); 195 NT_STATUS_NOT_OK_RETURN(nt_status); 196 197 if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { 198 union netr_Validation validation; 199 200 nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); 201 SAFE_FREE(response.extra_data.data); 202 NT_STATUS_NOT_OK_RETURN(nt_status); 203 204 validation.sam3 = &info3; 205 nt_status = make_server_info_netlogon_validation(mem_ctx, 206 user_info->client.account_name, 207 3, &validation, 208 server_info); 209 return nt_status; 210 } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { 211 DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " 212 "but did not include the required info3 reply!\n", 213 user_info->client.domain_name, user_info->client.account_name)); 214 return NT_STATUS_INSUFFICIENT_LOGON_INFO; 215 } else if (NT_STATUS_IS_OK(nt_status)) { 216 DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " 217 "but no error code is available!\n", 218 user_info->client.domain_name, user_info->client.account_name)); 219 return NT_STATUS_NO_LOGON_SERVERS; 220 } 221 222 return nt_status; 223} 224 225struct winbind_check_password_state { 226 struct winbind_SamLogon req; 227}; 228 229/* 230 Authenticate a user with a challenge/response 231 using IRPC to the winbind task 232*/ 233static NTSTATUS winbind_check_password(struct auth_method_context *ctx, 234 TALLOC_CTX *mem_ctx, 235 const struct auth_usersupplied_info *user_info, 236 struct auth_serversupplied_info **server_info) 237{ 238 NTSTATUS status; 239 struct server_id *winbind_servers; 240 struct winbind_check_password_state *s; 241 const struct auth_usersupplied_info *user_info_new; 242 struct netr_IdentityInfo *identity_info; 243 244 s = talloc(mem_ctx, struct winbind_check_password_state); 245 NT_STATUS_HAVE_NO_MEMORY(s); 246 247 winbind_servers = irpc_servers_byname(ctx->auth_ctx->msg_ctx, s, "winbind_server"); 248 if ((winbind_servers == NULL) || (winbind_servers[0].id == 0)) { 249 DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " 250 "no winbind_server running!\n", 251 user_info->client.domain_name, user_info->client.account_name)); 252 return NT_STATUS_NO_LOGON_SERVERS; 253 } 254 255 if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { 256 struct netr_PasswordInfo *password_info; 257 258 status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_HASH, 259 user_info, &user_info_new); 260 NT_STATUS_NOT_OK_RETURN(status); 261 user_info = user_info_new; 262 263 password_info = talloc(s, struct netr_PasswordInfo); 264 NT_STATUS_HAVE_NO_MEMORY(password_info); 265 266 password_info->lmpassword = *user_info->password.hash.lanman; 267 password_info->ntpassword = *user_info->password.hash.nt; 268 269 identity_info = &password_info->identity_info; 270 s->req.in.logon_level = 1; 271 s->req.in.logon.password= password_info; 272 } else { 273 struct netr_NetworkInfo *network_info; 274 const uint8_t *challenge; 275 276 status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, 277 user_info, &user_info_new); 278 NT_STATUS_NOT_OK_RETURN(status); 279 user_info = user_info_new; 280 281 network_info = talloc(s, struct netr_NetworkInfo); 282 NT_STATUS_HAVE_NO_MEMORY(network_info); 283 284 status = auth_get_challenge(ctx->auth_ctx, &challenge); 285 NT_STATUS_NOT_OK_RETURN(status); 286 287 memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); 288 289 network_info->nt.length = user_info->password.response.nt.length; 290 network_info->nt.data = user_info->password.response.nt.data; 291 292 network_info->lm.length = user_info->password.response.lanman.length; 293 network_info->lm.data = user_info->password.response.lanman.data; 294 295 identity_info = &network_info->identity_info; 296 s->req.in.logon_level = 2; 297 s->req.in.logon.network = network_info; 298 } 299 300 identity_info->domain_name.string = user_info->client.domain_name; 301 identity_info->parameter_control = user_info->logon_parameters; /* see MSV1_0_* */ 302 identity_info->logon_id_low = 0; 303 identity_info->logon_id_high = 0; 304 identity_info->account_name.string = user_info->client.account_name; 305 identity_info->workstation.string = user_info->workstation_name; 306 307 s->req.in.validation_level = 3; 308 309 status = IRPC_CALL(ctx->auth_ctx->msg_ctx, winbind_servers[0], 310 winbind, WINBIND_SAMLOGON, 311 &s->req, s); 312 NT_STATUS_NOT_OK_RETURN(status); 313 314 status = make_server_info_netlogon_validation(mem_ctx, 315 user_info->client.account_name, 316 s->req.in.validation_level, 317 &s->req.out.validation, 318 server_info); 319 NT_STATUS_NOT_OK_RETURN(status); 320 321 return NT_STATUS_OK; 322} 323 324/* 325 Authenticate a user with a challenge/response 326 using the samba3 winbind protocol via libwbclient 327*/ 328static NTSTATUS winbind_check_password_wbclient(struct auth_method_context *ctx, 329 TALLOC_CTX *mem_ctx, 330 const struct auth_usersupplied_info *user_info, 331 struct auth_serversupplied_info **server_info) 332{ 333 struct wbcAuthUserParams params; 334 struct wbcAuthUserInfo *info = NULL; 335 struct wbcAuthErrorInfo *err = NULL; 336 wbcErr wbc_status; 337 NTSTATUS nt_status; 338 struct netr_SamInfo3 info3; 339 union netr_Validation validation; 340 341 342 /* Send off request */ 343 const struct auth_usersupplied_info *user_info_temp; 344 nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, 345 AUTH_PASSWORD_RESPONSE, 346 user_info, &user_info_temp); 347 if (!NT_STATUS_IS_OK(nt_status)) { 348 return nt_status; 349 } 350 user_info = user_info_temp; 351 352 ZERO_STRUCT(params); 353 ZERO_STRUCT(info3); 354 /*params.flags = WBFLAG_PAM_INFO3_NDR;*/ 355 356 params.parameter_control = user_info->logon_parameters; 357 params.parameter_control |= WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | 358 WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT; 359 params.level = WBC_AUTH_USER_LEVEL_RESPONSE; 360 361 params.account_name = user_info->client.account_name; 362 params.domain_name = user_info->client.domain_name; 363 params.workstation_name = user_info->workstation_name; 364 365 d_fprintf(stderr, "looking up %s@%s logging in from %s\n", 366 params.account_name, params.domain_name, 367 params.workstation_name); 368 369 memcpy(params.password.response.challenge, 370 ctx->auth_ctx->challenge.data.data, 371 sizeof(params.password.response.challenge)); 372 373 params.password.response.lm_length = 374 user_info->password.response.lanman.length; 375 params.password.response.nt_length = 376 user_info->password.response.nt.length; 377 378 params.password.response.lm_data = 379 user_info->password.response.lanman.data; 380 params.password.response.nt_data = 381 user_info->password.response.nt.data; 382 383 wbc_status = wbcAuthenticateUserEx(¶ms, &info, &err); 384 if (!WBC_ERROR_IS_OK(wbc_status)) { 385 DEBUG(1, ("error was %s (0x%08x)\nerror message was '%s'\n", 386 err->nt_string, err->nt_status, err->display_string)); 387 388 nt_status = NT_STATUS(err->nt_status); 389 wbcFreeMemory(err); 390 NT_STATUS_NOT_OK_RETURN(nt_status); 391 } 392 nt_status = get_info3_from_wbcAuthUserInfo(mem_ctx, 393 lp_iconv_convenience(ctx->auth_ctx->lp_ctx), 394 info, &info3); 395 wbcFreeMemory(info); 396 NT_STATUS_NOT_OK_RETURN(nt_status); 397 398 validation.sam3 = &info3; 399 nt_status = make_server_info_netlogon_validation(mem_ctx, 400 user_info->client.account_name, 401 3, &validation, server_info); 402 return nt_status; 403 404} 405 406static const struct auth_operations winbind_samba3_ops = { 407 .name = "winbind_samba3", 408 .get_challenge = auth_get_challenge_not_implemented, 409 .want_check = winbind_want_check, 410 .check_password = winbind_check_password_samba3 411}; 412 413static const struct auth_operations winbind_ops = { 414 .name = "winbind", 415 .get_challenge = auth_get_challenge_not_implemented, 416 .want_check = winbind_want_check, 417 .check_password = winbind_check_password 418}; 419 420static const struct auth_operations winbind_wbclient_ops = { 421 .name = "winbind_wbclient", 422 .get_challenge = auth_get_challenge_not_implemented, 423 .want_check = winbind_want_check, 424 .check_password = winbind_check_password_wbclient 425}; 426 427_PUBLIC_ NTSTATUS auth_winbind_init(void) 428{ 429 NTSTATUS ret; 430 431 ret = auth_register(&winbind_samba3_ops); 432 if (!NT_STATUS_IS_OK(ret)) { 433 DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n")); 434 return ret; 435 } 436 437 ret = auth_register(&winbind_ops); 438 if (!NT_STATUS_IS_OK(ret)) { 439 DEBUG(0,("Failed to register 'winbind' auth backend!\n")); 440 return ret; 441 } 442 443 ret = auth_register(&winbind_wbclient_ops); 444 if (!NT_STATUS_IS_OK(ret)) { 445 DEBUG(0,("Failed to register 'winbind_wbclient' auth backend!\n")); 446 return ret; 447 } 448 449 return NT_STATUS_OK; 450} 451