2010-08-27 01:57:26 +04:00
/*
Unix SMB / CIFS implementation .
Authentication utility functions
Copyright ( C ) Simo Sorce 2010
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-03-25 04:28:05 +03:00
# include "auth.h"
2010-09-01 01:09:39 +04:00
# include "librpc/gen_ndr/krb5pac.h"
2011-02-25 00:30:16 +03:00
# include "nsswitch/libwbclient/wbclient.h"
2011-03-22 18:50:02 +03:00
# include "passdb.h"
2010-08-27 01:57:26 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_AUTH
# ifdef HAVE_KRB5
NTSTATUS get_user_from_kerberos_info ( TALLOC_CTX * mem_ctx ,
const char * cli_name ,
const char * princ_name ,
struct PAC_LOGON_INFO * logon_info ,
bool * is_mapped ,
bool * mapped_to_guest ,
char * * ntuser ,
char * * ntdomain ,
char * * username ,
struct passwd * * _pw )
{
NTSTATUS status ;
char * domain = NULL ;
char * realm = NULL ;
char * user = NULL ;
char * p ;
2010-11-09 23:07:25 +03:00
char * fuser = NULL ;
char * unixuser = NULL ;
2010-08-27 01:57:26 +04:00
struct passwd * pw = NULL ;
DEBUG ( 3 , ( " Kerberos ticket principal name is [%s] \n " , princ_name ) ) ;
p = strchr_m ( princ_name , ' @ ' ) ;
if ( ! p ) {
DEBUG ( 3 , ( " [%s] Doesn't look like a valid principal \n " ,
princ_name ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
user = talloc_strndup ( mem_ctx , princ_name , p - princ_name ) ;
if ( ! user ) {
return NT_STATUS_NO_MEMORY ;
}
realm = talloc_strdup ( talloc_tos ( ) , p + 1 ) ;
if ( ! realm ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! strequal ( realm , lp_realm ( ) ) ) {
DEBUG ( 3 , ( " Ticket for foreign realm %s@%s \n " , user , realm ) ) ;
if ( ! lp_allow_trusted_domains ( ) ) {
return NT_STATUS_LOGON_FAILURE ;
}
}
2011-10-22 00:10:43 +04:00
if ( logon_info & & logon_info - > info3 . base . logon_domain . string ) {
2010-08-27 01:57:26 +04:00
domain = talloc_strdup ( mem_ctx ,
2011-10-22 00:10:43 +04:00
logon_info - > info3 . base . logon_domain . string ) ;
2010-08-27 01:57:26 +04:00
if ( ! domain ) {
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 10 , ( " Domain is [%s] (using PAC) \n " , domain ) ) ;
} else {
/* If we have winbind running, we can (and must) shorten the
username by using the short netbios name . Otherwise we will
have inconsistent user names . With Kerberos , we get the
fully qualified realm , with ntlmssp we get the short
name . And even w2k3 does use ntlmssp if you for example
connect to an ip address . */
wbcErr wbc_status ;
struct wbcDomainInfo * info = NULL ;
DEBUG ( 10 , ( " Mapping [%s] to short name using winbindd \n " ,
realm ) ) ;
wbc_status = wbcDomainInfo ( realm , & info ) ;
if ( WBC_ERROR_IS_OK ( wbc_status ) ) {
domain = talloc_strdup ( mem_ctx ,
info - > short_name ) ;
wbcFreeMemory ( info ) ;
} else {
DEBUG ( 3 , ( " Could not find short name: %s \n " ,
wbcErrorString ( wbc_status ) ) ) ;
domain = talloc_strdup ( mem_ctx , realm ) ;
}
if ( ! domain ) {
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 10 , ( " Domain is [%s] (using Winbind) \n " , domain ) ) ;
}
2010-11-09 23:07:25 +03:00
fuser = talloc_asprintf ( mem_ctx ,
" %s%c%s " ,
domain ,
* lp_winbind_separator ( ) ,
user ) ;
if ( ! fuser ) {
return NT_STATUS_NO_MEMORY ;
}
2010-08-27 01:57:26 +04:00
2010-11-09 23:07:25 +03:00
* is_mapped = map_username ( mem_ctx , fuser , & fuser ) ;
if ( ! fuser ) {
return NT_STATUS_NO_MEMORY ;
}
2012-02-11 20:52:07 +04:00
* mapped_to_guest = false ;
2010-08-27 01:57:26 +04:00
2010-11-09 23:07:25 +03:00
pw = smb_getpwnam ( mem_ctx , fuser , & unixuser , true ) ;
2010-08-27 01:57:26 +04:00
if ( pw ) {
2010-11-09 23:07:25 +03:00
if ( ! unixuser ) {
return NT_STATUS_NO_MEMORY ;
}
2010-08-27 01:57:26 +04:00
/* if a real user check pam account restrictions */
/* only really perfomed if "obey pam restriction" is true */
/* do this before an eventual mapping to guest occurs */
status = smb_pam_accountcheck ( pw - > pw_name , cli_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " PAM account restrictions prevent user "
" [%s] login \n " , unixuser ) ) ;
return status ;
}
}
if ( ! pw ) {
/* this was originally the behavior of Samba 2.2, if a user
did not have a local uid but has been authenticated , then
map them to a guest account */
if ( lp_map_to_guest ( ) = = MAP_TO_GUEST_ON_BAD_UID ) {
* mapped_to_guest = true ;
2010-11-09 23:07:25 +03:00
fuser = talloc_strdup ( mem_ctx , lp_guestaccount ( ) ) ;
if ( ! fuser ) {
return NT_STATUS_NO_MEMORY ;
}
pw = smb_getpwnam ( mem_ctx , fuser , & unixuser , true ) ;
2010-08-27 01:57:26 +04:00
}
/* extra sanity check that the guest account is valid */
if ( ! pw ) {
DEBUG ( 1 , ( " Username %s is invalid on this system \n " ,
fuser ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
}
2010-11-09 23:07:25 +03:00
if ( ! unixuser ) {
return NT_STATUS_NO_MEMORY ;
}
2010-08-27 01:57:26 +04:00
* username = talloc_strdup ( mem_ctx , unixuser ) ;
if ( ! * username ) {
return NT_STATUS_NO_MEMORY ;
}
* ntuser = user ;
* ntdomain = domain ;
* _pw = pw ;
return NT_STATUS_OK ;
}
2010-08-27 02:48:46 +04:00
2011-02-11 03:50:37 +03:00
NTSTATUS make_session_info_krb5 ( TALLOC_CTX * mem_ctx ,
2010-08-27 02:48:46 +04:00
char * ntuser ,
char * ntdomain ,
char * username ,
struct passwd * pw ,
struct PAC_LOGON_INFO * logon_info ,
2011-02-11 03:50:37 +03:00
bool mapped_to_guest , bool username_was_mapped ,
DATA_BLOB * session_key ,
2011-07-18 07:06:47 +04:00
struct auth_session_info * * session_info )
2010-08-27 02:48:46 +04:00
{
NTSTATUS status ;
2011-02-11 03:50:37 +03:00
struct auth_serversupplied_info * server_info ;
2010-08-27 02:48:46 +04:00
if ( mapped_to_guest ) {
2011-02-11 03:50:37 +03:00
status = make_server_info_guest ( mem_ctx , & server_info ) ;
2010-08-27 02:48:46 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " make_server_info_guest failed: %s! \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
} else if ( logon_info ) {
/* pass the unmapped username here since map_username()
will be called again in make_server_info_info3 ( ) */
status = make_server_info_info3 ( mem_ctx ,
ntuser , ntdomain ,
2011-02-11 03:50:37 +03:00
& server_info ,
2010-08-27 02:48:46 +04:00
& logon_info - > info3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " make_server_info_info3 failed: %s! \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
} else {
/*
* We didn ' t get a PAC , we have to make up the user
* ourselves . Try to ask the pdb backend to provide
* SID consistency with ntlmssp session setup
*/
struct samu * sampass ;
/* The stupid make_server_info_XX functions here
don ' t take a talloc context . */
struct auth_serversupplied_info * tmp = NULL ;
sampass = samu_new ( talloc_tos ( ) ) ;
if ( sampass = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( pdb_getsampwnam ( sampass , username ) ) {
DEBUG ( 10 , ( " found user %s in passdb, calling "
" make_server_info_sam \n " , username ) ) ;
status = make_server_info_sam ( & tmp , sampass ) ;
} else {
/*
* User not in passdb , make it up artificially
*/
DEBUG ( 10 , ( " didn't find user %s in passdb, calling "
" make_server_info_pw \n " , username ) ) ;
status = make_server_info_pw ( & tmp , username , pw ) ;
}
2011-09-12 17:50:31 +04:00
2010-08-27 02:48:46 +04:00
TALLOC_FREE ( sampass ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " make_server_info_[sam|pw] failed: %s! \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
2011-09-12 22:23:17 +04:00
/* Steal tmp server info into the server_info pointer. */
server_info = talloc_move ( mem_ctx , & tmp ) ;
2010-08-27 02:48:46 +04:00
/* make_server_info_pw does not set the domain. Without this
* we end up with the local netbios name in substitutions for
* % D . */
2011-02-11 03:50:37 +03:00
if ( server_info - > info3 ! = NULL ) {
2011-10-22 00:10:43 +04:00
server_info - > info3 - > base . logon_domain . string =
2011-02-11 03:50:37 +03:00
talloc_strdup ( server_info - > info3 , ntdomain ) ;
2010-08-27 02:48:46 +04:00
}
2011-02-10 13:04:01 +03:00
}
2011-02-11 03:50:37 +03:00
server_info - > nss_token | = username_was_mapped ;
2010-08-27 02:48:46 +04:00
2011-07-26 07:37:36 +04:00
status = create_local_token ( mem_ctx , server_info , session_key , ntuser , session_info ) ;
2011-02-11 03:50:37 +03:00
talloc_free ( server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " failed to create local token: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
2010-08-27 02:48:46 +04:00
}
return NT_STATUS_OK ;
}
2010-08-27 01:57:26 +04:00
# else /* HAVE_KRB5 */
NTSTATUS get_user_from_kerberos_info ( TALLOC_CTX * mem_ctx ,
const char * cli_name ,
const char * princ_name ,
struct PAC_LOGON_INFO * logon_info ,
bool * is_mapped ,
bool * mapped_to_guest ,
char * * ntuser ,
char * * ntdomain ,
char * * username ,
struct passwd * * _pw )
{
return NT_STATUS_NOT_IMPLEMENTED ;
}
2010-08-27 02:48:46 +04:00
2011-02-11 03:50:37 +03:00
NTSTATUS make_session_info_krb5 ( TALLOC_CTX * mem_ctx ,
2010-08-27 02:48:46 +04:00
char * ntuser ,
char * ntdomain ,
char * username ,
struct passwd * pw ,
struct PAC_LOGON_INFO * logon_info ,
2011-02-11 03:50:37 +03:00
bool mapped_to_guest , bool username_was_mapped ,
DATA_BLOB * session_key ,
2011-07-20 05:40:02 +04:00
struct auth_session_info * * session_info )
2010-08-27 02:48:46 +04:00
{
return NT_STATUS_NOT_IMPLEMENTED ;
}
2010-08-27 01:57:26 +04:00
# endif /* HAVE_KRB5 */