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"
30 #include "librpc/gen_ndr/ndr_netlogon.h"
32 const char *user_attrs
[] = {
33 /* required for the krb5 kdc */
37 "servicePrincipalName",
38 "msDS-KeyVersionNumber",
52 /* check 'allowed workstations' */
55 /* required for server_info, not access control: */
70 const char *domain_ref_attrs
[] = {"nETBIOSName", "nCName",
71 "dnsRoot", "objectClass", NULL
};
74 /****************************************************************************
75 Do a specific test for a SAM_ACCOUNT being vaild for this connection
76 (ie not disabled, expired and the like).
77 ****************************************************************************/
78 _PUBLIC_ NTSTATUS
authsam_account_ok(TALLOC_CTX
*mem_ctx
,
79 struct ldb_context
*sam_ctx
,
80 uint32_t logon_parameters
,
81 struct ldb_message
*msg
,
82 struct ldb_message
*msg_domain_ref
,
83 const char *logon_workstation
,
84 const char *name_for_logs
)
87 const char *workstation_list
;
89 NTTIME must_change_time
;
92 struct ldb_dn
*domain_dn
= samdb_result_dn(sam_ctx
, mem_ctx
, msg_domain_ref
, "nCName", ldb_dn_new(mem_ctx
, sam_ctx
, NULL
));
95 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs
));
97 acct_flags
= samdb_result_acct_flags(msg
, "userAccountControl");
99 acct_expiry
= samdb_result_nttime(msg
, "accountExpires", 0);
100 must_change_time
= samdb_result_force_password_change(sam_ctx
, mem_ctx
,
102 last_set_time
= samdb_result_nttime(msg
, "pwdLastSet", 0);
104 workstation_list
= samdb_result_string(msg
, "userWorkstations", NULL
);
106 /* Quit if the account was disabled. */
107 if (acct_flags
& ACB_DISABLED
) {
108 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs
));
109 return NT_STATUS_ACCOUNT_DISABLED
;
112 /* Quit if the account was locked out. */
113 if (acct_flags
& ACB_AUTOLOCK
) {
114 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs
));
115 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
118 /* Test account expire time */
119 unix_to_nt_time(&now
, time(NULL
));
120 if (now
> acct_expiry
) {
121 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs
));
122 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
123 nt_time_string(mem_ctx
, acct_expiry
)));
124 return NT_STATUS_ACCOUNT_EXPIRED
;
127 if (!(acct_flags
& ACB_PWNOEXP
)) {
128 /* check for immediate expiry "must change at next logon" */
129 if (must_change_time
== 0 && last_set_time
!= 0) {
130 DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n",
132 return NT_STATUS_PASSWORD_MUST_CHANGE
;
135 /* check for expired password */
136 if ((must_change_time
!= 0) && (must_change_time
< now
)) {
137 DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n",
139 DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n",
140 nt_time_string(mem_ctx
, must_change_time
)));
141 return NT_STATUS_PASSWORD_EXPIRED
;
145 /* Test workstation. Workstation list is comma separated. */
146 if (logon_workstation
&& workstation_list
&& *workstation_list
) {
147 BOOL invalid_ws
= True
;
149 const char **workstations
= str_list_make(mem_ctx
, workstation_list
, ",");
151 for (i
= 0; workstations
&& workstations
[i
]; i
++) {
152 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
153 workstations
[i
], logon_workstation
));
155 if (strequal(workstations
[i
], logon_workstation
) == 0) {
161 talloc_free(workstations
);
164 return NT_STATUS_INVALID_WORKSTATION
;
168 if (acct_flags
& ACB_DOMTRUST
) {
169 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs
));
170 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
173 if (!(logon_parameters
& MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
)) {
174 if (acct_flags
& ACB_SVRTRUST
) {
175 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs
));
176 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
179 if (!(logon_parameters
& MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
)) {
180 if (acct_flags
& ACB_WSTRUST
) {
181 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs
));
182 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
189 _PUBLIC_ NTSTATUS
authsam_make_server_info(TALLOC_CTX
*mem_ctx
, struct ldb_context
*sam_ctx
,
190 struct ldb_message
*msg
,
191 struct ldb_message
*msg_domain_ref
,
192 DATA_BLOB user_sess_key
, DATA_BLOB lm_sess_key
,
193 struct auth_serversupplied_info
**_server_info
)
195 struct auth_serversupplied_info
*server_info
;
196 struct ldb_message
**group_msgs
;
198 const char *group_attrs
[3] = { "sAMAccountType", "objectSid", NULL
};
199 /* find list of sids */
200 struct dom_sid
**groupSIDs
= NULL
;
201 struct dom_sid
*account_sid
;
202 struct dom_sid
*primary_group_sid
;
204 struct ldb_dn
*ncname
;
207 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
209 group_ret
= gendb_search(sam_ctx
,
210 tmp_ctx
, NULL
, &group_msgs
, group_attrs
,
211 "(&(member=%s)(sAMAccountType=*))",
212 ldb_dn_get_linearized(msg
->dn
));
213 if (group_ret
== -1) {
214 talloc_free(tmp_ctx
);
215 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
218 server_info
= talloc(mem_ctx
, struct auth_serversupplied_info
);
219 NT_STATUS_HAVE_NO_MEMORY(server_info
);
222 groupSIDs
= talloc_array(server_info
, struct dom_sid
*, group_ret
);
223 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
);
226 /* Need to unroll some nested groups, but not aliases */
227 for (i
= 0; i
< group_ret
; i
++) {
228 groupSIDs
[i
] = samdb_result_dom_sid(groupSIDs
,
229 group_msgs
[i
], "objectSid");
230 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
[i
]);
233 talloc_free(tmp_ctx
);
235 account_sid
= samdb_result_dom_sid(server_info
, msg
, "objectSid");
236 NT_STATUS_HAVE_NO_MEMORY(account_sid
);
238 primary_group_sid
= dom_sid_dup(server_info
, account_sid
);
239 NT_STATUS_HAVE_NO_MEMORY(primary_group_sid
);
241 rid
= samdb_result_uint(msg
, "primaryGroupID", ~0);
244 primary_group_sid
= groupSIDs
[0];
246 primary_group_sid
= NULL
;
249 primary_group_sid
->sub_auths
[primary_group_sid
->num_auths
-1] = rid
;
252 server_info
->account_sid
= account_sid
;
253 server_info
->primary_group_sid
= primary_group_sid
;
255 server_info
->n_domain_groups
= group_ret
;
256 server_info
->domain_groups
= groupSIDs
;
258 server_info
->account_name
= talloc_steal(server_info
, samdb_result_string(msg
, "sAMAccountName", NULL
));
260 server_info
->domain_name
= talloc_steal(server_info
, samdb_result_string(msg_domain_ref
, "nETBIOSName", NULL
));
262 str
= samdb_result_string(msg
, "displayName", "");
263 server_info
->full_name
= talloc_strdup(server_info
, str
);
264 NT_STATUS_HAVE_NO_MEMORY(server_info
->full_name
);
266 str
= samdb_result_string(msg
, "scriptPath", "");
267 server_info
->logon_script
= talloc_strdup(server_info
, str
);
268 NT_STATUS_HAVE_NO_MEMORY(server_info
->logon_script
);
270 str
= samdb_result_string(msg
, "profilePath", "");
271 server_info
->profile_path
= talloc_strdup(server_info
, str
);
272 NT_STATUS_HAVE_NO_MEMORY(server_info
->profile_path
);
274 str
= samdb_result_string(msg
, "homeDirectory", "");
275 server_info
->home_directory
= talloc_strdup(server_info
, str
);
276 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_directory
);
278 str
= samdb_result_string(msg
, "homeDrive", "");
279 server_info
->home_drive
= talloc_strdup(server_info
, str
);
280 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_drive
);
282 server_info
->logon_server
= talloc_strdup(server_info
, lp_netbios_name());
283 NT_STATUS_HAVE_NO_MEMORY(server_info
->logon_server
);
285 server_info
->last_logon
= samdb_result_nttime(msg
, "lastLogon", 0);
286 server_info
->last_logoff
= samdb_result_nttime(msg
, "lastLogoff", 0);
287 server_info
->acct_expiry
= samdb_result_nttime(msg
, "accountExpires", 0);
288 server_info
->last_password_change
= samdb_result_nttime(msg
, "pwdLastSet", 0);
290 ncname
= samdb_result_dn(sam_ctx
, mem_ctx
, msg_domain_ref
, "nCName", NULL
);
292 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
294 server_info
->allow_password_change
295 = samdb_result_allow_password_change(sam_ctx
, mem_ctx
,
296 ncname
, msg
, "pwdLastSet");
297 server_info
->force_password_change
298 = samdb_result_force_password_change(sam_ctx
, mem_ctx
,
301 server_info
->logon_count
= samdb_result_uint(msg
, "logonCount", 0);
302 server_info
->bad_password_count
= samdb_result_uint(msg
, "badPwdCount", 0);
304 server_info
->acct_flags
= samdb_result_acct_flags(msg
, "userAccountControl");
306 server_info
->user_session_key
= user_sess_key
;
307 server_info
->lm_session_key
= lm_sess_key
;
309 server_info
->authenticated
= True
;
311 *_server_info
= server_info
;
316 _PUBLIC_ NTSTATUS
sam_get_results_principal(struct ldb_context
*sam_ctx
,
317 TALLOC_CTX
*mem_ctx
, const char *principal
,
318 struct ldb_message
***msgs
,
319 struct ldb_message
***msgs_domain_ref
)
321 struct ldb_dn
*user_dn
, *domain_dn
;
323 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
325 struct ldb_dn
*partitions_basedn
= samdb_partitions_dn(sam_ctx
, mem_ctx
);
328 return NT_STATUS_NO_MEMORY
;
331 nt_status
= crack_user_principal_name(sam_ctx
, tmp_ctx
, principal
, &user_dn
, &domain_dn
);
332 if (!NT_STATUS_IS_OK(nt_status
)) {
333 talloc_free(tmp_ctx
);
337 /* grab domain info from the reference */
338 ret
= gendb_search(sam_ctx
, tmp_ctx
, partitions_basedn
, msgs_domain_ref
, domain_ref_attrs
,
339 "(ncName=%s)", ldb_dn_get_linearized(domain_dn
));
342 talloc_free(tmp_ctx
);
343 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
346 /* pull the user attributes */
347 ret
= gendb_search_dn(sam_ctx
, tmp_ctx
, user_dn
, msgs
, user_attrs
);
349 talloc_free(tmp_ctx
);
350 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
352 talloc_steal(mem_ctx
, *msgs
);
353 talloc_steal(mem_ctx
, *msgs_domain_ref
);
354 talloc_free(tmp_ctx
);
359 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
360 NTSTATUS
sam_get_server_info_principal(TALLOC_CTX
*mem_ctx
, const char *principal
,
361 struct auth_serversupplied_info
**server_info
)
364 DATA_BLOB user_sess_key
= data_blob(NULL
, 0);
365 DATA_BLOB lm_sess_key
= data_blob(NULL
, 0);
367 struct ldb_message
**msgs
;
368 struct ldb_message
**msgs_domain_ref
;
369 struct ldb_context
*sam_ctx
;
371 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
373 return NT_STATUS_NO_MEMORY
;
376 sam_ctx
= samdb_connect(tmp_ctx
, system_session(tmp_ctx
));
377 if (sam_ctx
== NULL
) {
378 talloc_free(tmp_ctx
);
379 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
382 nt_status
= sam_get_results_principal(sam_ctx
, tmp_ctx
, principal
,
383 &msgs
, &msgs_domain_ref
);
384 if (!NT_STATUS_IS_OK(nt_status
)) {
388 nt_status
= authsam_make_server_info(tmp_ctx
, sam_ctx
, msgs
[0], msgs_domain_ref
[0],
389 user_sess_key
, lm_sess_key
,
391 if (NT_STATUS_IS_OK(nt_status
)) {
392 talloc_steal(mem_ctx
, *server_info
);
394 talloc_free(tmp_ctx
);