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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "system/time.h"
25 #include "auth/auth.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "libcli/security/security.h"
29 #include "libcli/ldap/ldap.h"
31 const char *user_attrs
[] = {
32 /* required for the krb5 kdc */
36 "servicePrincipalName",
37 "msDS-KeyVersionNumber",
51 /* check 'allowed workstations' */
54 /* required for server_info, not access control: */
69 const char *domain_ref_attrs
[] = {"nETBIOSName", "nCName",
70 "dnsRoot", "objectClass", NULL
};
73 /****************************************************************************
74 Do a specific test for a SAM_ACCOUNT being vaild for this connection
75 (ie not disabled, expired and the like).
76 ****************************************************************************/
77 _PUBLIC_ NTSTATUS
authsam_account_ok(TALLOC_CTX
*mem_ctx
,
78 struct ldb_context
*sam_ctx
,
79 uint32_t logon_parameters
,
80 struct ldb_message
*msg
,
81 struct ldb_message
*msg_domain_ref
,
82 const char *logon_workstation
,
83 const char *name_for_logs
)
86 const char *workstation_list
;
88 NTTIME must_change_time
;
91 struct ldb_dn
*domain_dn
= samdb_result_dn(mem_ctx
, msg_domain_ref
, "nCName", ldb_dn_new(mem_ctx
));
94 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs
));
96 acct_flags
= samdb_result_acct_flags(msg
, "userAccountControl");
98 acct_expiry
= samdb_result_nttime(msg
, "accountExpires", 0);
99 must_change_time
= samdb_result_force_password_change(sam_ctx
, mem_ctx
,
101 last_set_time
= samdb_result_nttime(msg
, "pwdLastSet", 0);
103 workstation_list
= samdb_result_string(msg
, "userWorkstations", NULL
);
105 /* Quit if the account was disabled. */
106 if (acct_flags
& ACB_DISABLED
) {
107 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs
));
108 return NT_STATUS_ACCOUNT_DISABLED
;
111 /* Quit if the account was locked out. */
112 if (acct_flags
& ACB_AUTOLOCK
) {
113 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs
));
114 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
117 /* Test account expire time */
118 unix_to_nt_time(&now
, time(NULL
));
119 if (now
> acct_expiry
) {
120 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs
));
121 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
122 nt_time_string(mem_ctx
, acct_expiry
)));
123 return NT_STATUS_ACCOUNT_EXPIRED
;
126 if (!(acct_flags
& ACB_PWNOEXP
)) {
127 /* check for immediate expiry "must change at next logon" */
128 if (must_change_time
== 0 && last_set_time
!= 0) {
129 DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n",
131 return NT_STATUS_PASSWORD_MUST_CHANGE
;
134 /* check for expired password */
135 if ((must_change_time
!= 0) && (must_change_time
< now
)) {
136 DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n",
138 DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n",
139 nt_time_string(mem_ctx
, must_change_time
)));
140 return NT_STATUS_PASSWORD_EXPIRED
;
144 /* Test workstation. Workstation list is comma separated. */
145 if (logon_workstation
&& workstation_list
&& *workstation_list
) {
146 BOOL invalid_ws
= True
;
148 const char **workstations
= str_list_make(mem_ctx
, workstation_list
, ",");
150 for (i
= 0; workstations
&& workstations
[i
]; i
++) {
151 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
152 workstations
[i
], logon_workstation
));
154 if (strequal(workstations
[i
], logon_workstation
) == 0) {
160 talloc_free(workstations
);
163 return NT_STATUS_INVALID_WORKSTATION
;
167 if (acct_flags
& ACB_DOMTRUST
) {
168 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs
));
169 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
172 if (!(logon_parameters
& MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
)) {
173 if (acct_flags
& ACB_SVRTRUST
) {
174 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs
));
175 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
178 if (!(logon_parameters
& MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
)) {
179 if (acct_flags
& ACB_WSTRUST
) {
180 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs
));
181 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
188 _PUBLIC_ NTSTATUS
authsam_make_server_info(TALLOC_CTX
*mem_ctx
, struct ldb_context
*sam_ctx
,
189 struct ldb_message
*msg
,
190 struct ldb_message
*msg_domain_ref
,
191 DATA_BLOB user_sess_key
, DATA_BLOB lm_sess_key
,
192 struct auth_serversupplied_info
**_server_info
)
194 struct auth_serversupplied_info
*server_info
;
195 struct ldb_message
**group_msgs
;
197 const char *group_attrs
[3] = { "sAMAccountType", "objectSid", NULL
};
198 /* find list of sids */
199 struct dom_sid
**groupSIDs
= NULL
;
200 struct dom_sid
*account_sid
;
201 struct dom_sid
*primary_group_sid
;
203 struct ldb_dn
*ncname
;
206 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
208 group_ret
= gendb_search(sam_ctx
,
209 tmp_ctx
, NULL
, &group_msgs
, group_attrs
,
210 "(&(member=%s)(sAMAccountType=*))",
211 ldb_dn_linearize(tmp_ctx
, msg
->dn
));
212 if (group_ret
== -1) {
213 talloc_free(tmp_ctx
);
214 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
217 server_info
= talloc(mem_ctx
, struct auth_serversupplied_info
);
218 NT_STATUS_HAVE_NO_MEMORY(server_info
);
221 groupSIDs
= talloc_array(server_info
, struct dom_sid
*, group_ret
);
222 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
);
225 /* Need to unroll some nested groups, but not aliases */
226 for (i
= 0; i
< group_ret
; i
++) {
227 groupSIDs
[i
] = samdb_result_dom_sid(groupSIDs
,
228 group_msgs
[i
], "objectSid");
229 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
[i
]);
232 talloc_free(tmp_ctx
);
234 account_sid
= samdb_result_dom_sid(server_info
, msg
, "objectSid");
235 NT_STATUS_HAVE_NO_MEMORY(account_sid
);
237 primary_group_sid
= dom_sid_dup(server_info
, account_sid
);
238 NT_STATUS_HAVE_NO_MEMORY(primary_group_sid
);
240 rid
= samdb_result_uint(msg
, "primaryGroupID", ~0);
243 primary_group_sid
= groupSIDs
[0];
245 primary_group_sid
= NULL
;
248 primary_group_sid
->sub_auths
[primary_group_sid
->num_auths
-1] = rid
;
251 server_info
->account_sid
= account_sid
;
252 server_info
->primary_group_sid
= primary_group_sid
;
254 server_info
->n_domain_groups
= group_ret
;
255 server_info
->domain_groups
= groupSIDs
;
257 server_info
->account_name
= talloc_steal(server_info
, samdb_result_string(msg
, "sAMAccountName", NULL
));
259 server_info
->domain_name
= talloc_steal(server_info
, samdb_result_string(msg_domain_ref
, "nETBIOSName", NULL
));
261 str
= samdb_result_string(msg
, "displayName", "");
262 server_info
->full_name
= talloc_strdup(server_info
, str
);
263 NT_STATUS_HAVE_NO_MEMORY(server_info
->full_name
);
265 str
= samdb_result_string(msg
, "scriptPath", "");
266 server_info
->logon_script
= talloc_strdup(server_info
, str
);
267 NT_STATUS_HAVE_NO_MEMORY(server_info
->logon_script
);
269 str
= samdb_result_string(msg
, "profilePath", "");
270 server_info
->profile_path
= talloc_strdup(server_info
, str
);
271 NT_STATUS_HAVE_NO_MEMORY(server_info
->profile_path
);
273 str
= samdb_result_string(msg
, "homeDirectory", "");
274 server_info
->home_directory
= talloc_strdup(server_info
, str
);
275 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_directory
);
277 str
= samdb_result_string(msg
, "homeDrive", "");
278 server_info
->home_drive
= talloc_strdup(server_info
, str
);
279 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_drive
);
281 server_info
->logon_server
= talloc_strdup(server_info
, lp_netbios_name());
282 NT_STATUS_HAVE_NO_MEMORY(server_info
->logon_server
);
284 server_info
->last_logon
= samdb_result_nttime(msg
, "lastLogon", 0);
285 server_info
->last_logoff
= samdb_result_nttime(msg
, "lastLogoff", 0);
286 server_info
->acct_expiry
= samdb_result_nttime(msg
, "accountExpires", 0);
287 server_info
->last_password_change
= samdb_result_nttime(msg
, "pwdLastSet", 0);
289 ncname
= samdb_result_dn(mem_ctx
, msg_domain_ref
, "nCName", NULL
);
291 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
293 server_info
->allow_password_change
294 = samdb_result_allow_password_change(sam_ctx
, mem_ctx
,
295 ncname
, msg
, "pwdLastSet");
296 server_info
->force_password_change
297 = samdb_result_force_password_change(sam_ctx
, mem_ctx
,
300 server_info
->logon_count
= samdb_result_uint(msg
, "logonCount", 0);
301 server_info
->bad_password_count
= samdb_result_uint(msg
, "badPwdCount", 0);
303 server_info
->acct_flags
= samdb_result_acct_flags(msg
, "userAccountControl");
305 server_info
->user_session_key
= user_sess_key
;
306 server_info
->lm_session_key
= lm_sess_key
;
308 server_info
->authenticated
= True
;
310 *_server_info
= server_info
;
315 _PUBLIC_ NTSTATUS
sam_get_results_principal(struct ldb_context
*sam_ctx
,
316 TALLOC_CTX
*mem_ctx
, const char *principal
,
317 struct ldb_message
***msgs
,
318 struct ldb_message
***msgs_domain_ref
)
320 struct ldb_dn
*user_dn
, *domain_dn
;
322 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
326 return NT_STATUS_NO_MEMORY
;
329 nt_status
= crack_user_principal_name(sam_ctx
, tmp_ctx
, principal
, &user_dn
, &domain_dn
);
330 if (!NT_STATUS_IS_OK(nt_status
)) {
331 talloc_free(tmp_ctx
);
335 /* grab domain info from the reference */
336 ret
= gendb_search(sam_ctx
, tmp_ctx
, NULL
, msgs_domain_ref
, domain_ref_attrs
,
337 "(ncName=%s)", ldb_dn_linearize(tmp_ctx
, domain_dn
));
340 talloc_free(tmp_ctx
);
341 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
344 /* pull the user attributes */
345 ret
= gendb_search_dn(sam_ctx
, tmp_ctx
, user_dn
, msgs
, user_attrs
);
347 talloc_free(tmp_ctx
);
348 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
350 talloc_steal(mem_ctx
, *msgs
);
351 talloc_steal(mem_ctx
, *msgs_domain_ref
);
352 talloc_free(tmp_ctx
);
357 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
358 NTSTATUS
sam_get_server_info_principal(TALLOC_CTX
*mem_ctx
, const char *principal
,
359 struct auth_serversupplied_info
**server_info
)
362 DATA_BLOB user_sess_key
= data_blob(NULL
, 0);
363 DATA_BLOB lm_sess_key
= data_blob(NULL
, 0);
365 struct ldb_message
**msgs
;
366 struct ldb_message
**msgs_domain_ref
;
367 struct ldb_context
*sam_ctx
;
369 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
371 return NT_STATUS_NO_MEMORY
;
374 sam_ctx
= samdb_connect(tmp_ctx
, system_session(tmp_ctx
));
375 if (sam_ctx
== NULL
) {
376 talloc_free(tmp_ctx
);
377 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
380 nt_status
= sam_get_results_principal(sam_ctx
, tmp_ctx
, principal
,
381 &msgs
, &msgs_domain_ref
);
382 if (!NT_STATUS_IS_OK(nt_status
)) {
386 nt_status
= authsam_make_server_info(tmp_ctx
, sam_ctx
, msgs
[0], msgs_domain_ref
[0],
387 user_sess_key
, lm_sess_key
,
389 if (NT_STATUS_IS_OK(nt_status
)) {
390 talloc_steal(mem_ctx
, *server_info
);
392 talloc_free(tmp_ctx
);