2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
5 Copyright (C) Gerald Carter 2003
6 Copyright (C) Stefan Metzmacher 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/time.h"
24 #include "auth/auth.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "libcli/security/security.h"
28 #include "libcli/ldap/ldap.h"
29 #include "librpc/gen_ndr/ndr_netlogon.h"
30 #include "param/param.h"
32 const char *user_attrs[] = {
33 /* required for the krb5 kdc */
37 "servicePrincipalName",
38 "msDS-KeyVersionNumber",
39 "supplementalCredentials",
52 /* check 'allowed workstations' */
55 /* required for server_info, not access control: */
70 const char *domain_ref_attrs[] = {"nETBIOSName", "nCName",
71 "dnsRoot", "objectClass", NULL};
73 /****************************************************************************
74 Check if a user is allowed to logon at this time. Note this is the
75 servers local time, as logon hours are just specified as a weekly
77 ****************************************************************************/
79 static BOOL logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
81 /* In logon hours first bit is Sunday from 12AM to 1AM */
82 const struct ldb_val *hours;
86 uint8_t bitmask, bitpos;
88 hours = ldb_msg_find_ldb_val(msg, "logonHours");
90 DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
94 if (hours->length != 168/8) {
95 DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
99 lasttime = time(NULL);
100 utctime = gmtime(&lasttime);
102 DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
107 /* find the corresponding byte and bit */
108 bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
109 bitmask = 1 << (bitpos % 8);
111 if (! (hours->data[bitpos/8] & bitmask)) {
112 struct tm *t = localtime(&lasttime);
114 asct = "INVALID TIME";
118 asct = "INVALID TIME";
122 DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
123 "logon at this time (%s).\n",
124 name_for_logs, asct ));
128 asct = asctime(utctime);
129 DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
130 name_for_logs, asct ? asct : "UNKNOWN TIME" ));
135 /****************************************************************************
136 Do a specific test for a SAM_ACCOUNT being vaild for this connection
137 (ie not disabled, expired and the like).
138 ****************************************************************************/
139 _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
140 struct ldb_context *sam_ctx,
141 uint32_t logon_parameters,
142 struct ldb_message *msg,
143 struct ldb_message *msg_domain_ref,
144 const char *logon_workstation,
145 const char *name_for_logs)
148 const char *workstation_list;
150 NTTIME must_change_time;
151 NTTIME last_set_time;
153 struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", ldb_dn_new(mem_ctx, sam_ctx, NULL));
156 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
158 acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
160 acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
161 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
163 last_set_time = samdb_result_nttime(msg, "pwdLastSet", 0);
165 workstation_list = samdb_result_string(msg, "userWorkstations", NULL);
167 /* Quit if the account was disabled. */
168 if (acct_flags & ACB_DISABLED) {
169 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
170 return NT_STATUS_ACCOUNT_DISABLED;
173 /* Quit if the account was locked out. */
174 if (acct_flags & ACB_AUTOLOCK) {
175 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
176 return NT_STATUS_ACCOUNT_LOCKED_OUT;
179 /* Test account expire time */
180 unix_to_nt_time(&now, time(NULL));
181 if (now > acct_expiry) {
182 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
183 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
184 nt_time_string(mem_ctx, acct_expiry)));
185 return NT_STATUS_ACCOUNT_EXPIRED;
188 if (!(acct_flags & ACB_PWNOEXP)) {
189 /* check for immediate expiry "must change at next logon" */
190 if (must_change_time == 0 && last_set_time != 0) {
191 DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n",
193 return NT_STATUS_PASSWORD_MUST_CHANGE;
196 /* check for expired password */
197 if ((must_change_time != 0) && (must_change_time < now)) {
198 DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n",
200 DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n",
201 nt_time_string(mem_ctx, must_change_time)));
202 return NT_STATUS_PASSWORD_EXPIRED;
206 /* Test workstation. Workstation list is comma separated. */
207 if (logon_workstation && workstation_list && *workstation_list) {
208 BOOL invalid_ws = True;
210 const char **workstations = str_list_make(mem_ctx, workstation_list, ",");
212 for (i = 0; workstations && workstations[i]; i++) {
213 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
214 workstations[i], logon_workstation));
216 if (strequal(workstations[i], logon_workstation)) {
222 talloc_free(workstations);
225 return NT_STATUS_INVALID_WORKSTATION;
229 if (!logon_hours_ok(msg, name_for_logs)) {
230 return NT_STATUS_INVALID_LOGON_HOURS;
233 if (acct_flags & ACB_DOMTRUST) {
234 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
235 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
238 if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
239 if (acct_flags & ACB_SVRTRUST) {
240 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
241 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
244 if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
245 if (acct_flags & ACB_WSTRUST) {
246 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
247 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
254 _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
255 struct ldb_message *msg,
256 struct ldb_message *msg_domain_ref,
257 DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key,
258 struct auth_serversupplied_info **_server_info)
260 struct auth_serversupplied_info *server_info;
261 struct ldb_message **group_msgs;
263 const char *group_attrs[3] = { "sAMAccountType", "objectSid", NULL };
264 /* find list of sids */
265 struct dom_sid **groupSIDs = NULL;
266 struct dom_sid *account_sid;
267 struct dom_sid *primary_group_sid;
269 struct ldb_dn *ncname;
272 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
274 group_ret = gendb_search(sam_ctx,
275 tmp_ctx, NULL, &group_msgs, group_attrs,
276 "(&(member=%s)(sAMAccountType=*))",
277 ldb_dn_get_linearized(msg->dn));
278 if (group_ret == -1) {
279 talloc_free(tmp_ctx);
280 return NT_STATUS_INTERNAL_DB_CORRUPTION;
283 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
284 NT_STATUS_HAVE_NO_MEMORY(server_info);
287 groupSIDs = talloc_array(server_info, struct dom_sid *, group_ret);
288 NT_STATUS_HAVE_NO_MEMORY(groupSIDs);
291 /* Need to unroll some nested groups, but not aliases */
292 for (i = 0; i < group_ret; i++) {
293 groupSIDs[i] = samdb_result_dom_sid(groupSIDs,
294 group_msgs[i], "objectSid");
295 NT_STATUS_HAVE_NO_MEMORY(groupSIDs[i]);
298 talloc_free(tmp_ctx);
300 account_sid = samdb_result_dom_sid(server_info, msg, "objectSid");
301 NT_STATUS_HAVE_NO_MEMORY(account_sid);
303 primary_group_sid = dom_sid_dup(server_info, account_sid);
304 NT_STATUS_HAVE_NO_MEMORY(primary_group_sid);
306 rid = samdb_result_uint(msg, "primaryGroupID", ~0);
309 primary_group_sid = groupSIDs[0];
311 primary_group_sid = NULL;
314 primary_group_sid->sub_auths[primary_group_sid->num_auths-1] = rid;
317 server_info->account_sid = account_sid;
318 server_info->primary_group_sid = primary_group_sid;
320 server_info->n_domain_groups = group_ret;
321 server_info->domain_groups = groupSIDs;
323 server_info->account_name = talloc_steal(server_info, samdb_result_string(msg, "sAMAccountName", NULL));
325 server_info->domain_name = talloc_steal(server_info, samdb_result_string(msg_domain_ref, "nETBIOSName", NULL));
327 str = samdb_result_string(msg, "displayName", "");
328 server_info->full_name = talloc_strdup(server_info, str);
329 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
331 str = samdb_result_string(msg, "scriptPath", "");
332 server_info->logon_script = talloc_strdup(server_info, str);
333 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
335 str = samdb_result_string(msg, "profilePath", "");
336 server_info->profile_path = talloc_strdup(server_info, str);
337 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
339 str = samdb_result_string(msg, "homeDirectory", "");
340 server_info->home_directory = talloc_strdup(server_info, str);
341 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
343 str = samdb_result_string(msg, "homeDrive", "");
344 server_info->home_drive = talloc_strdup(server_info, str);
345 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
347 server_info->logon_server = talloc_strdup(server_info, lp_netbios_name(global_loadparm));
348 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_server);
350 server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
351 server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0);
352 server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
353 server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0);
355 ncname = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", NULL);
357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
359 server_info->allow_password_change
360 = samdb_result_allow_password_change(sam_ctx, mem_ctx,
361 ncname, msg, "pwdLastSet");
362 server_info->force_password_change
363 = samdb_result_force_password_change(sam_ctx, mem_ctx,
366 server_info->logon_count = samdb_result_uint(msg, "logonCount", 0);
367 server_info->bad_password_count = samdb_result_uint(msg, "badPwdCount", 0);
369 server_info->acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
371 server_info->user_session_key = user_sess_key;
372 server_info->lm_session_key = lm_sess_key;
374 server_info->authenticated = True;
376 *_server_info = server_info;
381 _PUBLIC_ NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
382 TALLOC_CTX *mem_ctx, const char *principal,
383 struct ldb_message ***msgs,
384 struct ldb_message ***msgs_domain_ref)
386 struct ldb_dn *user_dn, *domain_dn;
388 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
390 struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
393 return NT_STATUS_NO_MEMORY;
396 nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, &user_dn, &domain_dn);
397 if (!NT_STATUS_IS_OK(nt_status)) {
398 talloc_free(tmp_ctx);
402 /* grab domain info from the reference */
403 ret = gendb_search(sam_ctx, tmp_ctx, partitions_basedn, msgs_domain_ref, domain_ref_attrs,
404 "(ncName=%s)", ldb_dn_get_linearized(domain_dn));
407 talloc_free(tmp_ctx);
408 return NT_STATUS_INTERNAL_DB_CORRUPTION;
411 /* pull the user attributes */
412 ret = gendb_search_dn(sam_ctx, tmp_ctx, user_dn, msgs, user_attrs);
414 talloc_free(tmp_ctx);
415 return NT_STATUS_INTERNAL_DB_CORRUPTION;
417 talloc_steal(mem_ctx, *msgs);
418 talloc_steal(mem_ctx, *msgs_domain_ref);
419 talloc_free(tmp_ctx);
424 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
425 NTSTATUS sam_get_server_info_principal(TALLOC_CTX *mem_ctx, const char *principal,
426 struct auth_serversupplied_info **server_info)
429 DATA_BLOB user_sess_key = data_blob(NULL, 0);
430 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
432 struct ldb_message **msgs;
433 struct ldb_message **msgs_domain_ref;
434 struct ldb_context *sam_ctx;
436 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
438 return NT_STATUS_NO_MEMORY;
441 sam_ctx = samdb_connect(tmp_ctx, system_session(tmp_ctx));
442 if (sam_ctx == NULL) {
443 talloc_free(tmp_ctx);
444 return NT_STATUS_INVALID_SYSTEM_SERVICE;
447 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
448 &msgs, &msgs_domain_ref);
449 if (!NT_STATUS_IS_OK(nt_status)) {
453 nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, msgs[0], msgs_domain_ref[0],
454 user_sess_key, lm_sess_key,
456 if (NT_STATUS_IS_OK(nt_status)) {
457 talloc_steal(mem_ctx, *server_info);
459 talloc_free(tmp_ctx);