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"
31 const char *user_attrs[] = {
32 /* required for the krb5 kdc */
36 "servicePrincipalName",
37 "msDS-KeyVersionNumber",
38 "supplementalCredentials",
51 /* check 'allowed workstations' */
54 /* required for server_info, not access control: */
69 const char *domain_ref_attrs[] = {"nETBIOSName", "nCName",
70 "dnsRoot", "objectClass", NULL};
72 /****************************************************************************
73 Check if a user is allowed to logon at this time. Note this is the
74 servers local time, as logon hours are just specified as a weekly
76 ****************************************************************************/
78 static BOOL logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
80 /* In logon hours first bit is Sunday from 12AM to 1AM */
81 const struct ldb_val *hours;
85 uint8_t bitmask, bitpos;
87 hours = ldb_msg_find_ldb_val(msg, "logonHours");
89 DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
93 if (hours->length != 168/8) {
94 DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
98 lasttime = time(NULL);
99 utctime = gmtime(&lasttime);
101 DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
106 /* find the corresponding byte and bit */
107 bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
108 bitmask = 1 << (bitpos % 8);
110 if (! (hours->data[bitpos/8] & bitmask)) {
111 struct tm *t = localtime(&lasttime);
113 asct = "INVALID TIME";
117 asct = "INVALID TIME";
121 DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
122 "logon at this time (%s).\n",
123 name_for_logs, asct ));
127 asct = asctime(utctime);
128 DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
129 name_for_logs, asct ? asct : "UNKNOWN TIME" ));
134 /****************************************************************************
135 Do a specific test for a SAM_ACCOUNT being vaild for this connection
136 (ie not disabled, expired and the like).
137 ****************************************************************************/
138 _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
139 struct ldb_context *sam_ctx,
140 uint32_t logon_parameters,
141 struct ldb_message *msg,
142 struct ldb_message *msg_domain_ref,
143 const char *logon_workstation,
144 const char *name_for_logs)
147 const char *workstation_list;
149 NTTIME must_change_time;
150 NTTIME last_set_time;
152 struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", ldb_dn_new(mem_ctx, sam_ctx, NULL));
155 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
157 acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
159 acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
160 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
162 last_set_time = samdb_result_nttime(msg, "pwdLastSet", 0);
164 workstation_list = samdb_result_string(msg, "userWorkstations", NULL);
166 /* Quit if the account was disabled. */
167 if (acct_flags & ACB_DISABLED) {
168 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
169 return NT_STATUS_ACCOUNT_DISABLED;
172 /* Quit if the account was locked out. */
173 if (acct_flags & ACB_AUTOLOCK) {
174 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
175 return NT_STATUS_ACCOUNT_LOCKED_OUT;
178 /* Test account expire time */
179 unix_to_nt_time(&now, time(NULL));
180 if (now > acct_expiry) {
181 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
182 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
183 nt_time_string(mem_ctx, acct_expiry)));
184 return NT_STATUS_ACCOUNT_EXPIRED;
187 if (!(acct_flags & ACB_PWNOEXP)) {
188 /* check for immediate expiry "must change at next logon" */
189 if (must_change_time == 0 && last_set_time != 0) {
190 DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n",
192 return NT_STATUS_PASSWORD_MUST_CHANGE;
195 /* check for expired password */
196 if ((must_change_time != 0) && (must_change_time < now)) {
197 DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n",
199 DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n",
200 nt_time_string(mem_ctx, must_change_time)));
201 return NT_STATUS_PASSWORD_EXPIRED;
205 /* Test workstation. Workstation list is comma separated. */
206 if (logon_workstation && workstation_list && *workstation_list) {
207 BOOL invalid_ws = True;
209 const char **workstations = str_list_make(mem_ctx, workstation_list, ",");
211 for (i = 0; workstations && workstations[i]; i++) {
212 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
213 workstations[i], logon_workstation));
215 if (strequal(workstations[i], logon_workstation)) {
221 talloc_free(workstations);
224 return NT_STATUS_INVALID_WORKSTATION;
228 if (!logon_hours_ok(msg, name_for_logs)) {
229 return NT_STATUS_INVALID_LOGON_HOURS;
232 if (acct_flags & ACB_DOMTRUST) {
233 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
234 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
237 if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
238 if (acct_flags & ACB_SVRTRUST) {
239 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
240 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
243 if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
244 if (acct_flags & ACB_WSTRUST) {
245 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
246 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
253 _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
254 struct ldb_message *msg,
255 struct ldb_message *msg_domain_ref,
256 DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key,
257 struct auth_serversupplied_info **_server_info)
259 struct auth_serversupplied_info *server_info;
260 struct ldb_message **group_msgs;
262 const char *group_attrs[3] = { "sAMAccountType", "objectSid", NULL };
263 /* find list of sids */
264 struct dom_sid **groupSIDs = NULL;
265 struct dom_sid *account_sid;
266 struct dom_sid *primary_group_sid;
268 struct ldb_dn *ncname;
271 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
273 group_ret = gendb_search(sam_ctx,
274 tmp_ctx, NULL, &group_msgs, group_attrs,
275 "(&(member=%s)(sAMAccountType=*))",
276 ldb_dn_get_linearized(msg->dn));
277 if (group_ret == -1) {
278 talloc_free(tmp_ctx);
279 return NT_STATUS_INTERNAL_DB_CORRUPTION;
282 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
283 NT_STATUS_HAVE_NO_MEMORY(server_info);
286 groupSIDs = talloc_array(server_info, struct dom_sid *, group_ret);
287 NT_STATUS_HAVE_NO_MEMORY(groupSIDs);
290 /* Need to unroll some nested groups, but not aliases */
291 for (i = 0; i < group_ret; i++) {
292 groupSIDs[i] = samdb_result_dom_sid(groupSIDs,
293 group_msgs[i], "objectSid");
294 NT_STATUS_HAVE_NO_MEMORY(groupSIDs[i]);
297 talloc_free(tmp_ctx);
299 account_sid = samdb_result_dom_sid(server_info, msg, "objectSid");
300 NT_STATUS_HAVE_NO_MEMORY(account_sid);
302 primary_group_sid = dom_sid_dup(server_info, account_sid);
303 NT_STATUS_HAVE_NO_MEMORY(primary_group_sid);
305 rid = samdb_result_uint(msg, "primaryGroupID", ~0);
308 primary_group_sid = groupSIDs[0];
310 primary_group_sid = NULL;
313 primary_group_sid->sub_auths[primary_group_sid->num_auths-1] = rid;
316 server_info->account_sid = account_sid;
317 server_info->primary_group_sid = primary_group_sid;
319 server_info->n_domain_groups = group_ret;
320 server_info->domain_groups = groupSIDs;
322 server_info->account_name = talloc_steal(server_info, samdb_result_string(msg, "sAMAccountName", NULL));
324 server_info->domain_name = talloc_steal(server_info, samdb_result_string(msg_domain_ref, "nETBIOSName", NULL));
326 str = samdb_result_string(msg, "displayName", "");
327 server_info->full_name = talloc_strdup(server_info, str);
328 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
330 str = samdb_result_string(msg, "scriptPath", "");
331 server_info->logon_script = talloc_strdup(server_info, str);
332 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
334 str = samdb_result_string(msg, "profilePath", "");
335 server_info->profile_path = talloc_strdup(server_info, str);
336 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
338 str = samdb_result_string(msg, "homeDirectory", "");
339 server_info->home_directory = talloc_strdup(server_info, str);
340 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
342 str = samdb_result_string(msg, "homeDrive", "");
343 server_info->home_drive = talloc_strdup(server_info, str);
344 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
346 server_info->logon_server = talloc_strdup(server_info, lp_netbios_name());
347 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_server);
349 server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
350 server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0);
351 server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
352 server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0);
354 ncname = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", NULL);
356 return NT_STATUS_INTERNAL_DB_CORRUPTION;
358 server_info->allow_password_change
359 = samdb_result_allow_password_change(sam_ctx, mem_ctx,
360 ncname, msg, "pwdLastSet");
361 server_info->force_password_change
362 = samdb_result_force_password_change(sam_ctx, mem_ctx,
365 server_info->logon_count = samdb_result_uint(msg, "logonCount", 0);
366 server_info->bad_password_count = samdb_result_uint(msg, "badPwdCount", 0);
368 server_info->acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
370 server_info->user_session_key = user_sess_key;
371 server_info->lm_session_key = lm_sess_key;
373 server_info->authenticated = True;
375 *_server_info = server_info;
380 _PUBLIC_ NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
381 TALLOC_CTX *mem_ctx, const char *principal,
382 struct ldb_message ***msgs,
383 struct ldb_message ***msgs_domain_ref)
385 struct ldb_dn *user_dn, *domain_dn;
387 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
389 struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
392 return NT_STATUS_NO_MEMORY;
395 nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, &user_dn, &domain_dn);
396 if (!NT_STATUS_IS_OK(nt_status)) {
397 talloc_free(tmp_ctx);
401 /* grab domain info from the reference */
402 ret = gendb_search(sam_ctx, tmp_ctx, partitions_basedn, msgs_domain_ref, domain_ref_attrs,
403 "(ncName=%s)", ldb_dn_get_linearized(domain_dn));
406 talloc_free(tmp_ctx);
407 return NT_STATUS_INTERNAL_DB_CORRUPTION;
410 /* pull the user attributes */
411 ret = gendb_search_dn(sam_ctx, tmp_ctx, user_dn, msgs, user_attrs);
413 talloc_free(tmp_ctx);
414 return NT_STATUS_INTERNAL_DB_CORRUPTION;
416 talloc_steal(mem_ctx, *msgs);
417 talloc_steal(mem_ctx, *msgs_domain_ref);
418 talloc_free(tmp_ctx);
423 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
424 NTSTATUS sam_get_server_info_principal(TALLOC_CTX *mem_ctx, const char *principal,
425 struct auth_serversupplied_info **server_info)
428 DATA_BLOB user_sess_key = data_blob(NULL, 0);
429 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
431 struct ldb_message **msgs;
432 struct ldb_message **msgs_domain_ref;
433 struct ldb_context *sam_ctx;
435 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
437 return NT_STATUS_NO_MEMORY;
440 sam_ctx = samdb_connect(tmp_ctx, system_session(tmp_ctx));
441 if (sam_ctx == NULL) {
442 talloc_free(tmp_ctx);
443 return NT_STATUS_INVALID_SYSTEM_SERVICE;
446 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
447 &msgs, &msgs_domain_ref);
448 if (!NT_STATUS_IS_OK(nt_status)) {
452 nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, msgs[0], msgs_domain_ref[0],
453 user_sess_key, lm_sess_key,
455 if (NT_STATUS_IS_OK(nt_status)) {
456 talloc_steal(mem_ctx, *server_info);
458 talloc_free(tmp_ctx);