2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/passwd.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../librpc/gen_ndr/netlogon.h"
27 #include "../libcli/security/security.h"
29 /* Fix up prototypes for OSX 10.4, where they're missing */
30 #ifndef HAVE_SETNETGRENT_PROTOTYPE
31 extern int setnetgrent(const char* netgroup
);
33 #ifndef HAVE_GETNETGRENT_PROTOTYPE
34 extern int getnetgrent(char **host
, char **user
, char **domain
);
36 #ifndef HAVE_ENDNETGRENT_PROTOTYPE
37 extern void endnetgrent(void);
40 enum server_allocated_state
{ SERVER_ALLOCATED_REQUIRED_YES
,
41 SERVER_ALLOCATED_REQUIRED_NO
,
42 SERVER_ALLOCATED_REQUIRED_ANY
};
44 static user_struct
*get_valid_user_struct_internal(
45 struct smbd_server_connection
*sconn
,
47 enum server_allocated_state server_allocated
)
52 if (vuid
== UID_FIELD_INVALID
)
55 usp
=sconn
->smb1
.sessions
.validated_users
;
56 for (;usp
;usp
=usp
->next
,count
++) {
57 if (vuid
== usp
->vuid
) {
58 switch (server_allocated
) {
59 case SERVER_ALLOCATED_REQUIRED_YES
:
60 if (usp
->session_info
== NULL
) {
64 case SERVER_ALLOCATED_REQUIRED_NO
:
65 if (usp
->session_info
!= NULL
) {
68 case SERVER_ALLOCATED_REQUIRED_ANY
:
72 DLIST_PROMOTE(sconn
->smb1
.sessions
.validated_users
,
82 /****************************************************************************
83 Check if a uid has been validated, and return an pointer to the user_struct
84 if it has. NULL if not. vuid is biased by an offset. This allows us to
85 tell random client vuid's (normally zero) from valid vuids.
86 ****************************************************************************/
88 user_struct
*get_valid_user_struct(struct smbd_server_connection
*sconn
,
91 return get_valid_user_struct_internal(sconn
, vuid
,
92 SERVER_ALLOCATED_REQUIRED_YES
);
95 bool is_partial_auth_vuid(struct smbd_server_connection
*sconn
, uint16 vuid
)
97 return (get_partial_auth_user_struct(sconn
, vuid
) != NULL
);
100 /****************************************************************************
101 Get the user struct of a partial NTLMSSP login
102 ****************************************************************************/
104 user_struct
*get_partial_auth_user_struct(struct smbd_server_connection
*sconn
,
107 return get_valid_user_struct_internal(sconn
, vuid
,
108 SERVER_ALLOCATED_REQUIRED_NO
);
111 /****************************************************************************
113 ****************************************************************************/
115 void invalidate_vuid(struct smbd_server_connection
*sconn
, uint16 vuid
)
117 user_struct
*vuser
= NULL
;
119 vuser
= get_valid_user_struct_internal(sconn
, vuid
,
120 SERVER_ALLOCATED_REQUIRED_ANY
);
125 session_yield(vuser
);
127 if (vuser
->auth_ntlmssp_state
) {
128 TALLOC_FREE(vuser
->auth_ntlmssp_state
);
131 DLIST_REMOVE(sconn
->smb1
.sessions
.validated_users
, vuser
);
133 /* clear the vuid from the 'cache' on each connection, and
134 from the vuid 'owner' of connections */
135 conn_clear_vuid_caches(sconn
, vuid
);
138 sconn
->smb1
.sessions
.num_validated_vuids
--;
141 /****************************************************************************
142 Invalidate all vuid entries for this process.
143 ****************************************************************************/
145 void invalidate_all_vuids(struct smbd_server_connection
*sconn
)
147 if (sconn
->using_smb2
) {
151 while (sconn
->smb1
.sessions
.validated_users
!= NULL
) {
152 invalidate_vuid(sconn
,
153 sconn
->smb1
.sessions
.validated_users
->vuid
);
157 static void increment_next_vuid(uint16_t *vuid
)
161 /* Check for vuid wrap. */
162 if (*vuid
== UID_FIELD_INVALID
) {
167 /****************************************************
168 Create a new partial auth user struct.
169 *****************************************************/
171 int register_initial_vuid(struct smbd_server_connection
*sconn
)
175 /* Paranoia check. */
176 if(lp_security() == SEC_SHARE
) {
177 smb_panic("register_initial_vuid: "
178 "Tried to register uid in security=share");
181 /* Limit allowed vuids to 16bits - VUID_OFFSET. */
182 if (sconn
->smb1
.sessions
.num_validated_vuids
>= 0xFFFF-VUID_OFFSET
) {
183 return UID_FIELD_INVALID
;
186 if((vuser
= talloc_zero(NULL
, user_struct
)) == NULL
) {
187 DEBUG(0,("register_initial_vuid: "
188 "Failed to talloc users struct!\n"));
189 return UID_FIELD_INVALID
;
192 /* Allocate a free vuid. Yes this is a linear search... */
193 while( get_valid_user_struct_internal(sconn
,
194 sconn
->smb1
.sessions
.next_vuid
,
195 SERVER_ALLOCATED_REQUIRED_ANY
) != NULL
) {
196 increment_next_vuid(&sconn
->smb1
.sessions
.next_vuid
);
199 DEBUG(10,("register_initial_vuid: allocated vuid = %u\n",
200 (unsigned int)sconn
->smb1
.sessions
.next_vuid
));
202 vuser
->vuid
= sconn
->smb1
.sessions
.next_vuid
;
205 * This happens in an unfinished NTLMSSP session setup. We
206 * need to allocate a vuid between the first and second calls
209 increment_next_vuid(&sconn
->smb1
.sessions
.next_vuid
);
210 sconn
->smb1
.sessions
.num_validated_vuids
++;
212 DLIST_ADD(sconn
->smb1
.sessions
.validated_users
, vuser
);
216 int register_homes_share(const char *username
)
221 result
= lp_servicenumber(username
);
223 DEBUG(3, ("Using static (or previously created) service for "
224 "user '%s'; path = '%s'\n", username
,
225 lp_pathname(result
)));
229 pwd
= Get_Pwnam_alloc(talloc_tos(), username
);
231 if ((pwd
== NULL
) || (pwd
->pw_dir
[0] == '\0')) {
232 DEBUG(3, ("No home directory defined for user '%s'\n",
238 DEBUG(3, ("Adding homes service for user '%s' using home directory: "
239 "'%s'\n", username
, pwd
->pw_dir
));
241 result
= add_home_service(username
, username
, pwd
->pw_dir
);
248 * register that a valid login has been performed, establish 'session'.
249 * @param session_info The token returned from the authentication process.
250 * (now 'owned' by register_existing_vuid)
252 * @param session_key The User session key for the login session (now also
253 * 'owned' by register_existing_vuid)
255 * @param respose_blob The NT challenge-response, if available. (May be
256 * freed after this call)
258 * @param smb_name The untranslated name of the user
260 * @return Newly allocated vuid, biased by an offset. (This allows us to
261 * tell random client vuid's (normally zero) from valid vuids.)
265 int register_existing_vuid(struct smbd_server_connection
*sconn
,
267 struct auth_session_info
*session_info
,
268 DATA_BLOB response_blob
)
271 bool guest
= security_session_user_level(session_info
, NULL
) < SECURITY_USER
;
273 vuser
= get_partial_auth_user_struct(sconn
, vuid
);
278 /* Use this to keep tabs on all our info from the authentication */
279 vuser
->session_info
= talloc_move(vuser
, &session_info
);
281 /* Make clear that we require the optional unix_token and unix_info in the source3 code */
282 SMB_ASSERT(vuser
->session_info
->unix_token
);
283 SMB_ASSERT(vuser
->session_info
->unix_info
);
285 DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n",
286 (unsigned int)vuser
->session_info
->unix_token
->uid
,
287 (unsigned int)vuser
->session_info
->unix_token
->gid
,
288 vuser
->session_info
->unix_info
->unix_name
,
289 vuser
->session_info
->unix_info
->sanitized_username
,
290 vuser
->session_info
->info
->domain_name
,
293 DEBUG(3, ("register_existing_vuid: User name: %s\t"
294 "Real name: %s\n", vuser
->session_info
->unix_info
->unix_name
,
295 vuser
->session_info
->info
->full_name
));
297 if (!vuser
->session_info
->security_token
) {
298 DEBUG(1, ("register_existing_vuid: session_info does not "
299 "contain a user_token - cannot continue\n"));
303 /* Make clear that we require the optional unix_token in the source3 code */
304 SMB_ASSERT(vuser
->session_info
->unix_token
);
306 DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, "
307 "and will be vuid %u\n", (int)vuser
->session_info
->unix_token
->uid
,
308 vuser
->session_info
->unix_info
->unix_name
, vuser
->vuid
));
310 if (!session_claim(sconn
, vuser
)) {
311 DEBUG(1, ("register_existing_vuid: Failed to claim session "
317 /* Register a home dir service for this user if
318 (a) This is not a guest connection,
319 (b) we have a home directory defined
320 (c) there s not an existing static share by that name
321 If a share exists by this name (autoloaded or not) reuse it . */
323 vuser
->homes_snum
= -1;
327 vuser
->homes_snum
= register_homes_share(
328 vuser
->session_info
->unix_info
->unix_name
);
331 if (srv_is_signing_negotiated(sconn
) &&
333 /* Try and turn on server signing on the first non-guest
335 srv_set_signing(sconn
,
336 vuser
->session_info
->session_key
,
340 /* fill in the current_user_info struct */
341 set_current_user_info(
342 vuser
->session_info
->unix_info
->sanitized_username
,
343 vuser
->session_info
->unix_info
->unix_name
,
344 vuser
->session_info
->info
->domain_name
);
351 invalidate_vuid(sconn
, vuid
);
353 return UID_FIELD_INVALID
;
356 /****************************************************************************
357 Add a name to the session users list.
358 ****************************************************************************/
360 void add_session_user(struct smbd_server_connection
*sconn
,
366 pw
= Get_Pwnam_alloc(talloc_tos(), user
);
372 if (sconn
->smb1
.sessions
.session_userlist
== NULL
) {
373 sconn
->smb1
.sessions
.session_userlist
= SMB_STRDUP(pw
->pw_name
);
377 if (in_list(pw
->pw_name
,sconn
->smb1
.sessions
.session_userlist
,false)) {
381 if (strlen(sconn
->smb1
.sessions
.session_userlist
) > 128 * 1024) {
382 DEBUG(3,("add_session_user: session userlist already "
387 if (asprintf(&tmp
, "%s %s",
388 sconn
->smb1
.sessions
.session_userlist
, pw
->pw_name
) == -1) {
389 DEBUG(3, ("asprintf failed\n"));
393 SAFE_FREE(sconn
->smb1
.sessions
.session_userlist
);
394 sconn
->smb1
.sessions
.session_userlist
= tmp
;
399 /****************************************************************************
400 In security=share mode we need to store the client workgroup, as that's
401 what Vista uses for the NTLMv2 calculation.
402 ****************************************************************************/
404 void add_session_workgroup(struct smbd_server_connection
*sconn
,
405 const char *workgroup
)
407 if (sconn
->smb1
.sessions
.session_workgroup
) {
408 SAFE_FREE(sconn
->smb1
.sessions
.session_workgroup
);
410 sconn
->smb1
.sessions
.session_workgroup
= smb_xstrdup(workgroup
);
413 /****************************************************************************
414 In security=share mode we need to return the client workgroup, as that's
415 what Vista uses for the NTLMv2 calculation.
416 ****************************************************************************/
418 const char *get_session_workgroup(struct smbd_server_connection
*sconn
)
420 return sconn
->smb1
.sessions
.session_workgroup
;
423 /****************************************************************************
424 Check if a username is valid.
425 ****************************************************************************/
427 static bool user_ok(const char *user
, int snum
)
433 if (lp_invalid_users(snum
)) {
434 char **invalid
= str_list_copy(talloc_tos(),
435 lp_invalid_users(snum
));
437 str_list_substitute(invalid
, "%S", lp_servicename(snum
))) {
439 /* This is used in sec=share only, so no current user
440 * around to pass to str_list_sub_basic() */
442 if ( invalid
&& str_list_sub_basic(invalid
, "", "") ) {
443 ret
= !user_in_list(talloc_tos(), user
,
444 (const char **)invalid
);
447 TALLOC_FREE(invalid
);
450 if (ret
&& lp_valid_users(snum
)) {
451 char **valid
= str_list_copy(talloc_tos(),
452 lp_valid_users(snum
));
454 str_list_substitute(valid
, "%S", lp_servicename(snum
)) ) {
456 /* This is used in sec=share only, so no current user
457 * around to pass to str_list_sub_basic() */
459 if ( valid
&& str_list_sub_basic(valid
, "", "") ) {
460 ret
= user_in_list(talloc_tos(), user
,
461 (const char **)valid
);
467 if (ret
&& lp_onlyuser(snum
)) {
468 char **user_list
= str_list_make_v3(
469 talloc_tos(), lp_username(snum
), NULL
);
471 str_list_substitute(user_list
, "%S",
472 lp_servicename(snum
))) {
473 ret
= user_in_list(talloc_tos(), user
,
474 (const char **)user_list
);
476 TALLOC_FREE(user_list
);
482 /****************************************************************************
483 Validate a group username entry. Return the username or NULL.
484 ****************************************************************************/
486 static char *validate_group(struct smbd_server_connection
*sconn
,
487 char *group
, DATA_BLOB password
,int snum
)
491 char *host
, *user
, *domain
;
492 struct auth_context
*actx
= sconn
->smb1
.negprot
.auth_context
;
493 bool enc
= sconn
->smb1
.negprot
.encrypted_passwords
;
495 while (getnetgrent(&host
, &user
, &domain
)) {
497 if (user_ok(user
, snum
) &&
498 password_ok(actx
, enc
,
499 get_session_workgroup(sconn
),
501 sconn
->remote_address
,
515 struct auth_context
*actx
= sconn
->smb1
.negprot
.auth_context
;
516 bool enc
= sconn
->smb1
.negprot
.encrypted_passwords
;
519 while ((gptr
= (struct group
*)getgrent())) {
520 if (strequal(gptr
->gr_name
,group
))
525 * As user_ok can recurse doing a getgrent(), we must
526 * copy the member list onto the heap before
527 * use. Bug pointed out by leon@eatworms.swmed.edu.
531 char *member_list
= NULL
;
536 for(i
= 0; gptr
->gr_mem
&& gptr
->gr_mem
[i
]; i
++) {
537 list_len
+= strlen(gptr
->gr_mem
[i
])+1;
541 member_list
= (char *)SMB_MALLOC(list_len
);
548 member
= member_list
;
550 for(i
= 0; gptr
->gr_mem
&& gptr
->gr_mem
[i
]; i
++) {
551 size_t member_len
= strlen(gptr
->gr_mem
[i
])+1;
553 DEBUG(10,("validate_group: = gr_mem = "
554 "%s\n", gptr
->gr_mem
[i
]));
556 strlcpy(member
, gptr
->gr_mem
[i
],
557 list_len
- (member
-member_list
));
558 member
+= member_len
;
563 member
= member_list
;
565 if (user_ok(member
,snum
) &&
566 password_ok(actx
, enc
,
567 get_session_workgroup(sconn
),
569 sconn
->remote_address
,
571 char *name
= talloc_strdup(talloc_tos(),
573 SAFE_FREE(member_list
);
577 DEBUG(10,("validate_group = member = %s\n",
580 member
+= strlen(member
) + 1;
583 SAFE_FREE(member_list
);
593 /****************************************************************************
594 Check for authority to login to a service with a given username/password.
595 Note this is *NOT* used when logging on using sessionsetup_and_X.
596 ****************************************************************************/
598 bool authorise_login(struct smbd_server_connection
*sconn
,
599 int snum
, fstring user
, DATA_BLOB password
,
603 struct auth_context
*actx
= sconn
->smb1
.negprot
.auth_context
;
604 bool enc
= sconn
->smb1
.negprot
.encrypted_passwords
;
606 #ifdef DEBUG_PASSWORD
607 DEBUG(100,("authorise_login: checking authorisation on "
608 "user=%s pass=%s\n", user
,password
.data
));
613 /* there are several possibilities:
614 1) login as the given user with given password
615 2) login as a previously registered username with the given
617 3) login as a session list username with the given password
618 4) login as a previously validated user/password pair
619 5) login as the "user =" user with given password
620 6) login as the "user =" user with no password
622 7) login as guest user with no password
624 if the service is guest_only then steps 1 to 5 are skipped
627 /* now check the list of session users */
630 char *user_list
= NULL
;
633 if (sconn
->smb1
.sessions
.session_userlist
)
634 user_list
= SMB_STRDUP(sconn
->smb1
.sessions
.session_userlist
);
636 user_list
= SMB_STRDUP("");
641 for (auser
= strtok_r(user_list
, LIST_SEP
, &saveptr
);
643 auser
= strtok_r(NULL
, LIST_SEP
, &saveptr
)) {
645 fstrcpy(user2
,auser
);
646 if (!user_ok(user2
,snum
))
649 if (password_ok(actx
, enc
,
650 get_session_workgroup(sconn
),
652 sconn
->remote_address
,
655 strlcpy(user
,user2
,sizeof(fstring
));
656 DEBUG(3,("authorise_login: ACCEPTED: session "
657 "list username (%s) and given "
658 "password ok\n", user
));
662 SAFE_FREE(user_list
);
665 /* check the user= fields and the given password */
666 if (!ok
&& lp_username(snum
)) {
667 TALLOC_CTX
*ctx
= talloc_tos();
669 char *user_list
= talloc_strdup(ctx
, lp_username(snum
));
676 user_list
= talloc_string_sub(ctx
,
679 lp_servicename(snum
));
685 for (auser
= strtok_r(user_list
, LIST_SEP
, &saveptr
);
687 auser
= strtok_r(NULL
, LIST_SEP
, &saveptr
)) {
689 auser
= validate_group(sconn
,auser
+1,
694 DEBUG(3,("authorise_login: ACCEPTED: "
695 "group username and given "
696 "password ok (%s)\n", user
));
700 fstrcpy(user2
,auser
);
701 if (user_ok(user2
,snum
) &&
702 password_ok(actx
, enc
,
703 get_session_workgroup(sconn
),
705 sconn
->remote_address
,
708 strlcpy(user
,user2
,sizeof(fstring
));
709 DEBUG(3,("authorise_login: ACCEPTED: "
710 "user list username and "
711 "given password ok (%s)\n",
720 /* check for a normal guest connection */
721 if (!ok
&& GUEST_OK(snum
)) {
722 struct passwd
*guest_pw
;
724 fstrcpy(guestname
,lp_guestaccount());
725 guest_pw
= Get_Pwnam_alloc(talloc_tos(), guestname
);
726 if (guest_pw
!= NULL
) {
727 strlcpy(user
,guestname
,sizeof(fstring
));
729 DEBUG(3,("authorise_login: ACCEPTED: guest account "
730 "and guest ok (%s)\n", user
));
732 DEBUG(0,("authorise_login: Invalid guest account "
733 "%s??\n",guestname
));
735 TALLOC_FREE(guest_pw
);
739 if (ok
&& !user_ok(user
, snum
)) {
740 DEBUG(0,("authorise_login: rejected invalid user %s\n",user
));