diff options
Diffstat (limited to 'usr/src/lib')
34 files changed, 1031 insertions, 809 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 704d7ba772..544a04dd33 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -19,11 +19,11 @@ # CDDL HEADER END # -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright (c) 2012, Joyent, Inc. All rights reserved. # Copyright (c) 2013 Gary Mills +# Copyright 2013 Nexenta Systems, Inc. All rights reserved. # Copyright 2014 Garrett D'Amore <garrett@damore.org> # Copyright (c) 2015 Gary Mills @@ -660,7 +660,8 @@ libexacct/demo: libexacct libproject libsocket libnsl libtsalarm: libpcp smbsrv: libsocket libnsl libmd libxnet libpthread librt \ libshare libidmap pkcs11 libsqlite libcryptoutil \ - libreparse libcmdutils libfakekernel + libreparse libcmdutils libresolv libsmbfs libuuid \ + libfakekernel libv12n: libds libuuid libvrrpadm: libsocket libdladm libscf libvscan: libscf diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c index 3138920e9b..967c8f7fe4 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + */ /* * lib/krb5/krb/get_in_tkt.c * @@ -130,6 +132,12 @@ send_as_request2(krb5_context context, reply.data = 0; + /* Solaris Kerberos (illumos) */ + if (krb5_getenv("MS_INTEROP")) { + /* Don't bother with UDP. */ + tcp_only = 1; + } + /* set the nonce if the caller expects us to do it */ if (request->nonce == 0) { if ((retval = krb5_timeofday(context, &time_now))) diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c index f3e159e6f9..10cdcdd502 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/send_tgs.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* @@ -176,6 +177,12 @@ krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions, if (!in_cred->ticket.length) return(KRB5_NO_TKT_SUPPLIED); + /* Solaris Kerberos (illumos) */ + if (krb5_getenv("MS_INTEROP")) { + /* Don't bother with UDP. */ + tcp_only = 1; + } + memset((char *)&tgsreq, 0, sizeof(tgsreq)); tgsreq.kdc_options = kdcoptions; diff --git a/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c b/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c index b15cbbf14b..b5ec62c921 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/inq_context.c @@ -1,4 +1,5 @@ /* + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -258,10 +259,12 @@ gss_krb5int_extract_authz_data_from_sec_context( const gss_OID desired_object, gss_buffer_set_t *data_set) { + gss_buffer_desc ad_data; OM_uint32 major_status; + krb5_error_code code; krb5_gss_ctx_id_rec *ctx; int ad_type = 0; - size_t i; + int i, j; *data_set = GSS_C_NO_BUFFER_SET; @@ -280,7 +283,6 @@ gss_krb5int_extract_authz_data_from_sec_context( if (ctx->authdata != NULL) { for (i = 0; ctx->authdata[i] != NULL; i++) { if (ctx->authdata[i]->ad_type == ad_type) { - gss_buffer_desc ad_data; ad_data.length = ctx->authdata[i]->length; ad_data.value = ctx->authdata[i]->contents; @@ -289,10 +291,39 @@ gss_krb5int_extract_authz_data_from_sec_context( &ad_data, data_set); if (GSS_ERROR(major_status)) break; + } else if (ctx->authdata[i]->ad_type == KRB5_AUTHDATA_IF_RELEVANT) { + /* + * Solaris Kerberos (illumos) + * Unwrap the AD-IF-RELEVANT object and look inside. + */ + krb5_authdata **ad_if_relevant = NULL; + code = krb5_decode_authdata_container(ctx->k5_context, + KRB5_AUTHDATA_IF_RELEVANT, + ctx->authdata[i], + &ad_if_relevant); + if (code != 0) + continue; + + for (j = 0; ad_if_relevant[j] != NULL; j++) { + if (ad_if_relevant[j]->ad_type == ad_type) { + ad_data.length = ad_if_relevant[j]->length; + ad_data.value = ad_if_relevant[j]->contents; + + major_status = generic_gss_add_buffer_set_member(minor_status, + &ad_data, data_set); + if (GSS_ERROR(major_status)) { + krb5_free_authdata(ctx->k5_context, ad_if_relevant); + goto break2; + } + } + } + krb5_free_authdata(ctx->k5_context, ad_if_relevant); + /* Solaris Kerberos (illumos) */ } } } +break2: if (GSS_ERROR(major_status)) { OM_uint32 tmp; diff --git a/usr/src/lib/libshare/smb/Makefile.com b/usr/src/lib/libshare/smb/Makefile.com index 0fc5f66142..ea69f59b22 100644 --- a/usr/src/lib/libshare/smb/Makefile.com +++ b/usr/src/lib/libshare/smb/Makefile.com @@ -22,7 +22,7 @@ # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# Copyright 2012 Nexenta Systems, Inc. All rights reserved. +# Copyright 2013 Nexenta Systems, Inc. All rights reserved. # LIBRARY = libshare_smb.a @@ -45,8 +45,7 @@ LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c) lintcheck := SRCS = $(LIBSRCS) LIBS = $(DYNLIB) -LDLIBS += -lshare -ldlpi -lnsl -lnvpair -lscf -lumem -lc -all install := LDLIBS += -lxml2 +LDLIBS += -lshare -lscf -luuid -ldlpi -lnsl -lnvpair -lxml2 -lumem -lc CFLAGS += $(CCVERBOSE) CERRWARN += -_gcc=-Wno-char-subscripts diff --git a/usr/src/lib/libsmbfs/Makefile b/usr/src/lib/libsmbfs/Makefile index 47c14c6bfa..b708bd0571 100644 --- a/usr/src/lib/libsmbfs/Makefile +++ b/usr/src/lib/libsmbfs/Makefile @@ -19,10 +19,11 @@ # CDDL HEADER END # # -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# # # lib/libsmbfs/Makefile @@ -30,7 +31,7 @@ include $(SRC)/lib/Makefile.lib -HDRS= smbfs_acl.h smbfs_api.h smb_keychain.h +HDRS= ntlmssp.h smbfs_acl.h smbfs_api.h smb_keychain.h spnego.h HDRDIR= netsmb ROOTHDRDIR= $(ROOT)/usr/include/netsmb diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com index a3ec0fb397..f5801a18db 100644 --- a/usr/src/lib/libsmbfs/Makefile.com +++ b/usr/src/lib/libsmbfs/Makefile.com @@ -23,6 +23,8 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# # # lib/libsmbfs/Makefile.com @@ -101,7 +103,7 @@ CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-unused-variable CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \ - -I$(SRCDIR) -I.. \ + -I$(SRCDIR) -I.. -I../netsmb \ -I$(SRC)/uts/common \ -I$(SRC)/common/smbclnt diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.h b/usr/src/lib/libsmbfs/netsmb/ntlmssp.h index 5f3e09ac0d..f4cfc34783 100644 --- a/usr/src/lib/libsmbfs/smb/ntlmssp.h +++ b/usr/src/lib/libsmbfs/netsmb/ntlmssp.h @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ @@ -37,6 +38,10 @@ * http://msdn.microsoft.com/en-us/library/cc236621(PROT.10).aspx */ +#ifdef __cplusplus +extern "C" { +#endif + /* * NTLMSSP Message Types * [MS-NLMP] sec. 2.2.1 @@ -82,4 +87,28 @@ #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 +/* + * NTLMSSP AV_PAIR types + * [MS-NLMP] sec. 2.2.2.1 + * + * The names are all LE-Unicode. + */ +typedef enum ntlmssp_AvId { + MsvAvEOL = 0, /* End Of List */ + MsvAvNbComputerName, /* server's NetBIOS name */ + MsvAvNbDomainName, /* server's NetBIOS domain */ + MsvAvDnsComputerName, /* server's DNS name */ + MsvAvDnsDomainName, /* server's DNS domain */ + MsvAvDnsTreeName, /* server's Forest name */ + MsvAvFlags, /* 32-bit (LE) flags */ + MsvAvTimestamp, /* 64-bit time, [MS-DTYP] sec. 2.3.1 */ + MsvAvRestrictions, /* struct, [MS-NLMP] sec. 2.2.2.2 */ + MsvAvTargetName, /* SPN of the server */ + MsvChannelBindings, /* MD5 hash of GSS challen bindings */ +} ntlmssp_AvId_t; + +#ifdef __cplusplus +} +#endif + #endif /* _NTLMSSP_H */ diff --git a/usr/src/lib/libsmbfs/netsmb/spnego.h b/usr/src/lib/libsmbfs/netsmb/spnego.h new file mode 100644 index 0000000000..1a60436740 --- /dev/null +++ b/usr/src/lib/libsmbfs/netsmb/spnego.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2002 Microsoft Corporation + * All rights reserved. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + * OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY + * AND/OR FITNESS FOR A PARTICULAR PURPOSE. + * + * Date - 10/08/2002 + * Author - Sanj Surati + */ + +/* + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * spnego.h + * + * SPNEGO Token Handler Header File + * + * Contains the definitions required to interpret and create + * SPNEGO tokens so that Kerberos GSS tokens can be + * Unpackaged/packaged. + */ + +#ifndef _SPNEGO_H +#define _SPNEGO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Type Definitions + */ + +/* + * Users of SPNEGO Token Handler API will request + * these as well as free them, + */ +typedef void* SPNEGO_TOKEN_HANDLE; + +/* + * Defines the element types that are found + * in each of the tokens. + */ + +typedef enum spnego_element_type +{ + spnego_element_min, /* Lower bound */ + + /* Init token elements */ + spnego_init_mechtypes, + spnego_init_reqFlags, + spnego_init_mechToken, + spnego_init_mechListMIC, + + /* Targ token elements */ + spnego_targ_negResult, + spnego_targ_supportedMech, + spnego_targ_responseToken, + spnego_targ_mechListMIC, + + spnego_element_max /* Upper bound */ + +} SPNEGO_ELEMENT_TYPE; + +/* + * Token Element Availability. Elements in both + * token types are optional. Since there are only + * 4 elements in each Token, we will allocate space + * to hold the information, but we need a way to + * indicate whether or not an element is available + */ + +#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0 +#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1 + +/* + * Token type values. SPNEGO has 2 token types: + * NegTokenInit and NegTokenTarg + */ + +#define SPNEGO_TOKEN_INIT 0 +#define SPNEGO_TOKEN_TARG 1 + +/* + * GSS Mechanism OID enumeration. We only really handle + * 3 different OIDs. These are stored in an array structure + * defined in the parsing code. + */ + +typedef enum spnego_mech_oid +{ + /* Init token elements */ + spnego_mech_oid_Kerberos_V5_Legacy, /* Really V5, but OID off by 1 */ + spnego_mech_oid_Kerberos_V5, + spnego_mech_oid_Spnego, + spnego_mech_oid_NTLMSSP, + spnego_mech_oid_NotUsed = -1 + +} SPNEGO_MECH_OID; + +/* + * Defines the negResult values. + */ + +typedef enum spnego_negResult +{ + spnego_negresult_success, + spnego_negresult_incomplete, + spnego_negresult_rejected, + spnego_negresult_NotUsed = -1 +} SPNEGO_NEGRESULT; + +/* + * Context Flags in NegTokenInit + */ + +/* + * ContextFlags values MUST be zero or a combination + * of the below + */ + +#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80 +#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40 +#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20 +#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10 +#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8 +#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4 +#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2 + +/* + * Mask to retrieve valid values. + */ + +#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE + +/* + * SPNEGO API return codes. + */ + +/* API function was successful */ +#define SPNEGO_E_SUCCESS 0 + +/* The supplied Token was invalid */ +#define SPNEGO_E_INVALID_TOKEN -1 + +/* An invalid length was encountered */ +#define SPNEGO_E_INVALID_LENGTH -2 + +/* The Token Parse failed */ +#define SPNEGO_E_PARSE_FAILED -3 + +/* The requested value was not found */ +#define SPNEGO_E_NOT_FOUND -4 + +/* The requested element is not available */ +#define SPNEGO_E_ELEMENT_UNAVAILABLE -5 + +/* Out of Memory */ +#define SPNEGO_E_OUT_OF_MEMORY -6 + +/* Not Implemented */ +#define SPNEGO_E_NOT_IMPLEMENTED -7 + +/* Invalid Parameter */ +#define SPNEGO_E_INVALID_PARAMETER -8 + +/* Token Handler encountered an unexpected OID */ +#define SPNEGO_E_UNEXPECTED_OID -9 + +/* The requested token was not found */ +#define SPNEGO_E_TOKEN_NOT_FOUND -10 + +/* An unexpected type was encountered in the encoding */ +#define SPNEGO_E_UNEXPECTED_TYPE -11 + +/* The buffer was too small */ +#define SPNEGO_E_BUFFER_TOO_SMALL -12 + +/* A Token Element was invalid (e.g. improper length or value) */ +#define SPNEGO_E_INVALID_ELEMENT -13 + +/* Miscelaneous API Functions */ + +/* Frees opaque data */ +void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken); + +/* Initializes SPNEGO_TOKEN structure from DER encoded binary data */ +int spnegoInitFromBinary(unsigned char *pbTokenData, unsigned long ulLength, + SPNEGO_TOKEN_HANDLE* phSpnegoToken); + +/* Initializes SPNEGO_TOKEN structure for a NegTokenInit type */ +int spnegoCreateNegTokenHint(SPNEGO_MECH_OID *pMechTypeList, int MechTypeCnt, + unsigned char *pbPrincipal, SPNEGO_TOKEN_HANDLE* phSpnegoToken); + +/* Initializes SPNEGO_TOKEN structure for a NegTokenInit type */ +int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char *pbMechToken, + unsigned long ulMechTokenLen, unsigned char *pbMechTokenMIC, + unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE *phSpnegoToken); + +/* Initializes SPNEGO_TOKEN structure for a NegTokenTarg type */ +int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, unsigned char *pbMechToken, + unsigned long ulMechTokenLen, unsigned char *pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken); + +/* Copies binary representation of SPNEGO Data into user supplied buffer */ +int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken, + unsigned char *pbTokenData, unsigned long *pulDataLen); + +/* Returns SPNEGO Token Type */ +int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int *piTokenType); + +/* Reading an Init Token */ + +/* Returns the Initial Mech Type in the MechList element in the NegInitToken. */ +int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken, + SPNEGO_MECH_OID MechOID, int *piMechTypeIndex); + +/* Returns the value from the context flags element in the NegInitToken */ +int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken, + unsigned char *pucContextFlags); + +/* Reading a Response Token */ + +/* + * Returns the value from the negResult element + * (Status code of GSS call - 0,1,2) + */ +int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken, + SPNEGO_NEGRESULT* pnegResult); + +/* Returns the Supported Mech Type from the NegTokenTarg. */ +int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken, + SPNEGO_MECH_OID* pMechOID); + +/* Reading either Token Type */ + +/* + * Returns the actual Mechanism data from the token + * (this is what is passed into GSS-API functions + */ +int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken, + unsigned char *pbTokenData, unsigned long *pulDataLen); + +/* Returns the Message Integrity BLOB in the token */ +int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken, + unsigned char *pbMICData, unsigned long *pulDataLen); + +#ifdef __cplusplus +} +#endif + +#endif /* _SPNEGO_H */ diff --git a/usr/src/lib/libsmbfs/smb/derparse.c b/usr/src/lib/libsmbfs/smb/derparse.c index f92da913c2..f21a277d5a 100644 --- a/usr/src/lib/libsmbfs/smb/derparse.c +++ b/usr/src/lib/libsmbfs/smb/derparse.c @@ -1,3 +1,4 @@ +// Copyright 2012 Nexenta Systems, Inc. All rights reserved. // Copyright (C) 2002 Microsoft Corporation // All rights reserved. // @@ -451,29 +452,37 @@ long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ) // Comments : // Helper function to calculate a MechList length. A mechlist consists // of a NegTokenInit sequence token, a sequence token for the MechList -// and finally a list of OIDs. In our case, we only really have one -// OID. +// and finally a list of OIDs. // //////////////////////////////////////////////////////////////////////////// -long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ) +long ASNDerCalcMechListLength( SPNEGO_MECH_OID *mechOidLst, int mechOidCnt, + long* pnInternalLength ) { - // First the OID - long nTotalLength = g_stcMechOIDList[mechoid].iLen; - - // Next add in a sequence token - nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); - - // Internal length is the length without the element sequence token - if ( NULL != pnInternalLength ) - { - *pnInternalLength = nTotalLength; - } - - // Finally add in the element's sequence token - nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); - - return nTotalLength; + // First the OID + SPNEGO_MECH_OID oid_idx; + long nTotalLength; + int i; + + nTotalLength = 0; + for (i = 0; i < mechOidCnt; i++) { + oid_idx = mechOidLst[i]; + nTotalLength += g_stcMechOIDList[oid_idx].iLen; + } + + // Next add in a sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Internal length is the length without the element sequence token + if ( NULL != pnInternalLength ) + { + *pnInternalLength = nTotalLength; + } + + // Finally add in the element's sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + return nTotalLength; } @@ -646,9 +655,12 @@ int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ) { - memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen ); + if (pbData != NULL) { + memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, + g_stcMechOIDList[eMechOID].iLen ); + } - return g_stcMechOIDList[eMechOID].iLen; + return g_stcMechOIDList[eMechOID].iLen; } @@ -671,27 +683,35 @@ int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ) // //////////////////////////////////////////////////////////////////////////// -long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ) +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt ) { - // First get the length - long nInternalLength = 0L; - long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength ); - long nTempLength = 0L; - - nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, + // First get the length + long nInternalLength = 0L; + long nMechListLength; + long nTempLength = 0L; + int i; + + nMechListLength = ASNDerCalcMechListLength(mechOidLst, mechOidCnt, &nInternalLength); + nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, NULL, nInternalLength ); - // Adjust the data pointer - pbData += nTempLength; + // Adjust the data pointer + pbData += nTempLength; + nInternalLength -= nTempLength; + + // Now write the Sequence token and the OID (the OID is a BLOB in the global + // structure. - // Now write the Sequence token and the OID (the OID is a BLOB in the global - // structure. + nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE, + NULL, nInternalLength); + pbData += nTempLength; - nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE, - g_stcMechOIDList[mechoid].ucOid, - g_stcMechOIDList[mechoid].iLen ); + for (i = 0; i < mechOidCnt; i++) { + nTempLength = ASNDerWriteOID( pbData, mechOidLst[i] ); + pbData += nTempLength; + } - return nMechListLength; + return nMechListLength; } diff --git a/usr/src/lib/libsmbfs/smb/derparse.h b/usr/src/lib/libsmbfs/smb/derparse.h index dcdf5828dc..b1801c8e1c 100644 --- a/usr/src/lib/libsmbfs/smb/derparse.h +++ b/usr/src/lib/libsmbfs/smb/derparse.h @@ -1,3 +1,4 @@ +// Copyright 2012 Nexenta Systems, Inc. All rights reserved. // Copyright (C) 2002 Microsoft Corporation // All rights reserved. // @@ -21,8 +22,6 @@ // ///////////////////////////////////////////////////////////// -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef __DERPARSE_H__ #define __DERPARSE_H__ @@ -178,12 +177,13 @@ int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long n int ASNDerCalcNumLengthBytes( long nLength ); long ASNDerCalcTokenLength( long nLength, long nDataLength ); long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ); -long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ); +long ASNDerCalcMechListLength( SPNEGO_MECH_OID *mechOidLst, int mechOidCnt, + long* pnInternalLength ); int ASNDerWriteLength( unsigned char* pbData, long nLength ); int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, unsigned char* pbTokenValue, long nLength ); int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ); -long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ); +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt ); int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, unsigned char ucType, unsigned char* pbTokenValue, long nLength ); diff --git a/usr/src/lib/libsmbfs/smb/llib-lsmbfs b/usr/src/lib/libsmbfs/smb/llib-lsmbfs index e8e05e4272..1096482541 100644 --- a/usr/src/lib/libsmbfs/smb/llib-lsmbfs +++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs @@ -22,6 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /*LINTLIBRARY*/ @@ -34,4 +36,5 @@ #include <netsmb/smb_keychain.h> #include <netsmb/smb_netshareenum.h> #include <netsmb/smb_rap.h> +#include <netsmb/spnego.h> diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers index 1c2a5d6fa9..24bffec63d 100644 --- a/usr/src/lib/libsmbfs/smb/mapfile-vers +++ b/usr/src/lib/libsmbfs/smb/mapfile-vers @@ -18,8 +18,8 @@ # CDDL HEADER END # # -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2013 Nexenta Systems, Inc. All rights reserved. # # @@ -151,6 +151,20 @@ SYMBOL_VERSION SUNWprivate { smbfs_set_default_user; smbutil_std_opts; + + spnegoCreateNegTokenHint; + spnegoCreateNegTokenInit; + spnegoCreateNegTokenTarg; + spnegoFreeData; + spnegoGetContextFlags; + spnegoGetMechListMIC; + spnegoGetMechToken; + spnegoGetNegotiationResult; + spnegoGetSupportedMechType; + spnegoGetTokenType; + spnegoInitFromBinary; + spnegoIsMechTypeAvailable; + spnegoTokenGetBinary; local: *; }; diff --git a/usr/src/lib/libsmbfs/smb/spnego.c b/usr/src/lib/libsmbfs/smb/spnego.c index 3e300cd606..a15303da30 100644 --- a/usr/src/lib/libsmbfs/smb/spnego.c +++ b/usr/src/lib/libsmbfs/smb/spnego.c @@ -1,3 +1,4 @@ +// Copyright 2012 Nexenta Systems, Inc. All rights reserved. // Copyright (C) 2002 Microsoft Corporation // All rights reserved. // @@ -21,10 +22,9 @@ // ///////////////////////////////////////////////////////////// -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <memory.h> #include "spnego.h" #include "derparse.h" @@ -89,6 +89,111 @@ int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SP ///////////////////////////////////////////////////////////////////////////// // // Function: +// spnegoCreateNegTokenHint +// +// Parameters: +// [in] pMechTypeList - List of MechTypes (OIDs) to include +// [in] MechTypeCnt - Length of MechTypes array +// [in] pbPrincipal - Principal name for MechListMIC +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type token +// from the supplied parameters. The token created is the "hint" +// used (for example) in the response to an SMB negotiate protocol. +// Returned data structure must be freed by calling spnegoFreeData(). +// +// The "hint" tells the client what authentication methods this +// server supports (the ones in the MechTypeList). The Principal +// name historically was the server's own SPN, but recent versions +// of windows only supply: "not_defined_in_RFC4178@please_ignore" +// So if you want to be nice to your clients, provide the host SPN, +// otherwise provide the bogus SPN string like recent windows. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoCreateNegTokenHint( SPNEGO_MECH_OID *pMechTypeList, int MechTypeCnt, + unsigned char *pbPrincipal, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn; + long nTokenLength = 0L; + long nInternalTokenLength = 0L; + unsigned long ulPrincipalLen; + unsigned char* pbMechListMIC; + unsigned long ulMechListMICLen; + unsigned char* pbTokenData = NULL; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + if ( NULL == ppSpnegoToken || NULL == pbPrincipal ) + return (SPNEGO_E_INVALID_PARAMETER); + + /* + * Get the actual token size + */ + ulPrincipalLen = strlen((char *)pbPrincipal); + ulMechListMICLen = ASNDerCalcElementLength( ulPrincipalLen, NULL ); + nReturn = CalculateMinSpnegoInitTokenSize( + 0, /* ulMechTokenLen */ + ulMechListMICLen, + pMechTypeList, + MechTypeCnt, + 0, /* nReqFlagsAvailable */ + &nTokenLength, + &nInternalTokenLength ); + if ( nReturn != SPNEGO_E_SUCCESS ) + return (nReturn); + + // Allocate a buffer to hold the data. + pbTokenData = calloc( 1, nTokenLength ); + + if ( NULL == pbTokenData ) + return ( SPNEGO_E_OUT_OF_MEMORY ); + + /* + * Construct the MechListMIC + */ + pbMechListMIC = pbTokenData + (nTokenLength - ulMechListMICLen); + (void) ASNDerWriteElement( pbMechListMIC, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, + GENERALSTR, pbPrincipal, ulPrincipalLen ); + + // Now write the token + nReturn = CreateSpnegoInitToken( + pMechTypeList, + MechTypeCnt, + 0, /* ContextFlags */ + NULL, 0, /* MechToken, len */ + pbMechListMIC, + ulMechListMICLen, + pbTokenData, + nTokenLength, + nInternalTokenLength ); + if ( nReturn != SPNEGO_E_SUCCESS ) { + free( pbTokenData ); + return (nReturn); + } + + // This will copy our allocated pointer, and ensure that the sructure cleans + // up the data later + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, + pbTokenData, nTokenLength, ppSpnegoToken ); + + // Cleanup on failure + if ( nReturn != SPNEGO_E_SUCCESS ) { + free( pbTokenData ); + return (nReturn); + } + + return (SPNEGO_E_SUCCESS); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: // spnegoCreateNegTokenInit // // Parameters: @@ -131,7 +236,7 @@ int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, // Get the actual token size if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen, - MechType, ( ucContextFlags != 0L ), + &MechType, 1, ( ucContextFlags != 0L ), &nTokenLength, &nInternalTokenLength ) ) == SPNEGO_E_SUCCESS ) { @@ -142,7 +247,7 @@ int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, { // Now write the token - if ( ( nReturn = CreateSpnegoInitToken( MechType, + if ( ( nReturn = CreateSpnegoInitToken( &MechType, 1, ucContextFlags, pbMechToken, ulMechTokenLen, pbMechListMIC, ulMechListMICLen, pbTokenData, @@ -227,11 +332,7 @@ int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, spnego_mech_oid_NotUsed == MechType ) && ( IsValidNegResult( spnegoNegResult ) || - spnego_negresult_NotUsed == spnegoNegResult ) && - - !( !IsValidMechOid( MechType ) && - ( spnego_negresult_success == spnegoNegResult || - spnego_negresult_incomplete == spnegoNegResult ) ) ) + spnego_negresult_NotUsed == spnegoNegResult ) ) { // Get the actual token size diff --git a/usr/src/lib/libsmbfs/smb/spnego.h b/usr/src/lib/libsmbfs/smb/spnego.h deleted file mode 100644 index 9865fbd85d..0000000000 --- a/usr/src/lib/libsmbfs/smb/spnego.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (C) 2002 Microsoft Corporation -// All rights reserved. -// -// THIS CODE AND INFORMATION IS PROVIDED "AS IS" -// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -// OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY -// AND/OR FITNESS FOR A PARTICULAR PURPOSE. -// -// Date - 10/08/2002 -// Author - Sanj Surati - -///////////////////////////////////////////////////////////// -// -// SPNEGO.H -// -// SPNEGO Token Handler Header File -// -// Contains the definitions required to interpret and create -// SPNEGO tokens so that Kerberos GSS tokens can be -// Unpackaged/packaged. -// -///////////////////////////////////////////////////////////// - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifndef __SPNEGO_H__ -#define __SPNEGO_H__ - -// C++ Specific -#if defined(__cplusplus) -extern "C" -{ -#endif - -// Type Definitions - -// -// Users of SPNEGO Token Handler API will request -// these as well as free them, -// -typedef void* SPNEGO_TOKEN_HANDLE; - -// -// Defines the element types that are found -// in each of the tokens. -// - -typedef enum spnego_element_type -{ - spnego_element_min, // Lower bound - - // Init token elements - spnego_init_mechtypes, - spnego_init_reqFlags, - spnego_init_mechToken, - spnego_init_mechListMIC, - - // Targ token elements - spnego_targ_negResult, - spnego_targ_supportedMech, - spnego_targ_responseToken, - spnego_targ_mechListMIC, - - spnego_element_max // Upper bound - -} SPNEGO_ELEMENT_TYPE; - -// -// Token Element Availability. Elements in both -// token types are optional. Since there are only -// 4 elements in each Token, we will allocate space -// to hold the information, but we need a way to -// indicate whether or not an element is available -// - -#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0 -#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1 - -// -// Token type values. SPNEGO has 2 token types: -// NegTokenInit and NegTokenTarg -// - -#define SPNEGO_TOKEN_INIT 0 -#define SPNEGO_TOKEN_TARG 1 - -// -// GSS Mechanism OID enumeration. We only really handle -// 3 different OIDs. These are stored in an array structure -// defined in the parsing code. -// - -typedef enum spnego_mech_oid -{ - // Init token elements - spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit - spnego_mech_oid_Kerberos_V5, - spnego_mech_oid_Spnego, - spnego_mech_oid_NTLMSSP, - spnego_mech_oid_NotUsed = -1 - -} SPNEGO_MECH_OID; - -// -// Defines the negResult values. -// - -typedef enum spnego_negResult -{ - spnego_negresult_success, - spnego_negresult_incomplete, - spnego_negresult_rejected, - spnego_negresult_NotUsed = -1 -} SPNEGO_NEGRESULT; - -// -// Context Flags in NegTokenInit -// - -// -// ContextFlags values MUST be zero or a combination -// of the below -// - -#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80 -#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40 -#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20 -#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10 -#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8 -#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4 -#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2 - -// -// Mask to retrieve valid values. -// - -#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags - -// -// SPNEGO API return codes. -// - -// API function was successful -#define SPNEGO_E_SUCCESS 0 - -// The supplied Token was invalid -#define SPNEGO_E_INVALID_TOKEN -1 - -// An invalid length was encountered -#define SPNEGO_E_INVALID_LENGTH -2 - -// The Token Parse failed -#define SPNEGO_E_PARSE_FAILED -3 - -// The requested value was not found -#define SPNEGO_E_NOT_FOUND -4 - -// The requested element is not available -#define SPNEGO_E_ELEMENT_UNAVAILABLE -5 - -// Out of Memory -#define SPNEGO_E_OUT_OF_MEMORY -6 - -// Not Implemented -#define SPNEGO_E_NOT_IMPLEMENTED -7 - -// Invalid Parameter -#define SPNEGO_E_INVALID_PARAMETER -8 - -// Token Handler encountered an unexpected OID -#define SPNEGO_E_UNEXPECTED_OID -9 - -// The requested token was not found -#define SPNEGO_E_TOKEN_NOT_FOUND -10 - -// An unexpected type was encountered in the encoding -#define SPNEGO_E_UNEXPECTED_TYPE -11 - -// The buffer was too small -#define SPNEGO_E_BUFFER_TOO_SMALL -12 - -// A Token Element was invalid (e.g. improper length or value) -#define SPNEGO_E_INVALID_ELEMENT -13 - -/* Miscelaneous API Functions */ - -// Frees opaque data -void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken ); - -// Initializes SPNEGO_TOKEN structure from DER encoded binary data -int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); - -// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the -// supplied parameters -int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, - unsigned char ucContextFlags, unsigned char* pbMechToken, - unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC, - unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); - -// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the -// supplied parameters -int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, - SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, - unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, - unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); - -// Copies binary representation of SPNEGO Data into user supplied buffer -int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, - unsigned long * pulDataLen ); - -// Returns SPNEGO Token Type -int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType ); - -/* Reading an Init Token */ - -// Returns the Initial Mech Type in the MechList element in the NegInitToken. -int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ); - -// Returns the value from the context flags element in the NegInitToken as an unsigned long -int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags ); - -/* Reading a Response Token */ - -// Returns the value from the negResult element (Status code of GSS call - 0,1,2) -int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult ); - -// Returns the Supported Mech Type from the NegTokenTarg. -int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID ); - -/* Reading either Token Type */ - -// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions -int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen ); - -// Returns the Message Integrity BLOB in the token -int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen ); - -// C++ Specific -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.c b/usr/src/lib/libsmbfs/smb/spnegoparse.c index e9f1e2781b..ea5fb03a70 100644 --- a/usr/src/lib/libsmbfs/smb/spnegoparse.c +++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c @@ -1,3 +1,4 @@ +// Copyright 2012 Nexenta Systems, Inc. All rights reserved. // Copyright (C) 2002 Microsoft Corporation // All rights reserved. // @@ -54,6 +55,7 @@ extern MECH_OID g_stcMechOIDList []; // Parameters: // [in] nMechTokenLength - Length of the MechToken Element // [in] nMechListMICLength - Length of the MechListMIC Element +// (or negHints, if no MechToken) // [in] mechOID - OID for MechList // [in] nReqFlagsAvailable - Is ContextFlags element available // [out] pnTokenSize - Filled out with total size of token @@ -75,7 +77,7 @@ extern MECH_OID g_stcMechOIDList []; //////////////////////////////////////////////////////////////////////////// int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, - long nMechListMICLength, SPNEGO_MECH_OID mechOid, + long nMechListMICLength, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt, int nReqFlagsAvailable, long* pnTokenSize, long* pnInternalTokenLength ) { @@ -87,7 +89,7 @@ int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, // We will calculate this by walking the token backwards - // Start with MIC Element + // Start with MIC Element (or negHints) if ( nMechListMICLength > 0L ) { nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL ); @@ -130,7 +132,7 @@ int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, } // Next is the MechList - This is REQUIRED - nTempLength += ASNDerCalcMechListLength( mechOid, NULL ); + nTempLength += ASNDerCalcMechListLength( mechOidLst, mechOidCnt, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) @@ -205,11 +207,12 @@ xEndTokenInitLength: // CreateSpnegoInitToken // // Parameters: -// [in] MechType - OID in MechList +// [in] pMechTypeList - OID array +// [in] MechTypeCnt - OID array length // [in] ucContextFlags - ContextFlags value // [in] pbMechToken - Mech Token Binary Data // [in] ulMechTokenLen - Length of Mech Token -// [in] pbMechListMIC - MechListMIC Binary Data +// [in] pbMechListMIC - MechListMIC Binary Data (or negHints) // [in] ulMechListMICn - Length of MechListMIC // [out] pbTokenData - Buffer to write token into. // [in] nTokenLength - Length of pbTokenData buffer @@ -227,9 +230,18 @@ xEndTokenInitLength: // backwards, so we always know how many bytes we will potentially be // writing out. // +// This function is also used to create an SPNEGO "hint", as described in +// [MS-SPNG] sec. 2.2.1 negTokenInit2. The "hint" looks almost identical +// to a NegTokenInit, but has a "negHints" field inserted before the MIC. +// A normal SPNEGO negTokenInit2 contains only the mech list and the +// negHints. To avoid a giant copy/paste of this function, we pass the +// negHints as the MIC arg, and pass NULL as the MechToken to indicate +// that we're creating a Hint rather than an Init, and use the correct +// type when writing out the MIC (or negHints) element. +// //////////////////////////////////////////////////////////////////////////// -int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, +int CreateSpnegoInitToken( SPNEGO_MECH_OID *pMechTypeList, long MechTypeCnt, unsigned char ucContextFlags, unsigned char* pbMechToken, unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, unsigned long ulMechListMICLen, unsigned char* pbTokenData, @@ -251,17 +263,22 @@ int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, // We will write the token out backwards to properly handle the cases // where the length bytes become adjustable - // Start with MIC Element + // Start with MIC Element (or negHints) if ( ulMechListMICLen > 0L ) { + unsigned char ucType; nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); - // Decrease the pbWriteTokenData, now we know the length and - // write it out. + // Decrease the pbWriteTokenData, now we know the length and write it out. + // Note: When MechTokenLen == 0, we're writing a negTokenInit2 and the + // MIC arg is really negHints, written as a constructed sequence. + // Otherwise we're writing a negTokenInit, and the MIC is an OCTETSTRING. + ucType = (ulMechTokenLen == 0) ? + SPNEGO_CONSTRUCTED_SEQUENCE : OCTETSTRING; pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, - OCTETSTRING, pbMechListMIC, ulMechListMICLen ); + ucType, pbMechListMIC, ulMechListMICLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; @@ -325,12 +342,12 @@ int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, } // IF ContextFlags // Next is the MechList - This is REQUIRED - nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength ); + nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; - nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType ); + nTempLength = ASNDerWriteMechList( pbWriteTokenData, pMechTypeList, MechTypeCnt ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; @@ -1281,8 +1298,6 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD long nElementLength = 0L; long nActualTokenLength = 0L; unsigned char* pbElements = NULL; - unsigned char * ptok; - long tlen, elen, len; // Point to the correct array switch( pSpnegoToken->ucTokenType ) @@ -1370,37 +1385,32 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, OCTETSTRING, spnego_init_mechToken, &pSpnegoToken->aElementArray[nCtr] ); - } + } break; - case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: + case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: // xA3 { // - // This is an OCTETSTRING which contains a message integrity BLOB. + // Don't yet know if this is a negTokenInit, or negTokenInit2. + // Unfortunately, both have the same type: SPNEGO_TOKEN_INIT + // If it's negTokenInit, this element should be an OCTETSTRING + // containing the MIC. If it's a negTokenInit2, this element + // should be an SPNEGO_CONSTRUCTED_SEQUENCE containing the + // negHints (GENERALSTR, ignored) // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, - OCTETSTRING, spnego_init_mechListMIC, - &pSpnegoToken->aElementArray[nCtr] ); - /* - * don't believe everything you read in RFCs (and MS - * sample code)... win2k is sending not an octet string, - * but a "general string", wrapped in a sequence. - */ - if (nReturn != SPNEGO_E_UNEXPECTED_TYPE) - break; - ptok = pbTokenData; - elen = nElementLength; - if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) - break; - elen -= tlen; - ptok += tlen; - - if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) - break; - elen -= tlen; - ptok += tlen; - nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]); + OCTETSTRING, spnego_init_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + + if (nReturn == SPNEGO_E_UNEXPECTED_TYPE) { + // This is really a negHints element. Check the type and length, + // but otherwise just ignore it. + long elen, tlen; + nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + nElementLength, nElementLength, + &elen, &tlen ); + } } break; @@ -1408,6 +1418,7 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD } else { + /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */ switch( pbElements[nCtr] ) { @@ -1453,12 +1464,13 @@ int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenD case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: { // - // This is an OCTETSTRING which specifies a message integrity BLOB. + // This is an OCTETSTRING, typically 16 bytes, + // which contains a message integrity BLOB. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, - OCTETSTRING, spnego_targ_mechListMIC, - &pSpnegoToken->aElementArray[nCtr] ); + OCTETSTRING, spnego_targ_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); } break; diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.h b/usr/src/lib/libsmbfs/smb/spnegoparse.h index b874dc453d..1f7fde7486 100644 --- a/usr/src/lib/libsmbfs/smb/spnegoparse.h +++ b/usr/src/lib/libsmbfs/smb/spnegoparse.h @@ -1,3 +1,4 @@ +// Copyright 2012 Nexenta Systems, Inc. All rights reserved. // Copyright (C) 2002 Microsoft Corporation // All rights reserved. // @@ -21,8 +22,6 @@ // ///////////////////////////////////////////////////////////// -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef __SPNEGOPARSE_H__ #define __SPNEGOPARSE_H__ @@ -136,13 +135,13 @@ int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechO int * piMechTypeIndex ); int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ); int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength, - SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable, + SPNEGO_MECH_OID *mechOid, int mechOidCnt, int nReqFlagsAvailable, long* plTokenSize, long* plInternalLength ); int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, long nMechTokenMIC, long* pnTokenSize, long* pnInternalTokenLength ); -int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, +int CreateSpnegoInitToken( SPNEGO_MECH_OID *MechTypeList, long nMechTypes, unsigned char ucContextFlags, unsigned char* pbMechToken, unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, unsigned long ulMechListMICLen, unsigned char* pbTokenData, diff --git a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com index d40fa8d629..20c8f74f77 100644 --- a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com +++ b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com @@ -51,6 +51,7 @@ OBJS_LOCAL = \ OBJS_FS_SMBSRV = \ smb_acl.o \ smb_alloc.o \ + smb_authenticate.o \ smb_close.o \ smb_common_open.o \ smb_common_transact.o \ diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h index 881535d2f3..685a760e16 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h @@ -70,6 +70,10 @@ extern void mlsvc_fini(void); extern DWORD mlsvc_netlogon(char *, char *); extern DWORD mlsvc_join(smb_domainex_t *, char *, char *); +extern void smb_logon_domain(smb_logon_t *, smb_token_t *); +extern uint32_t smb_decode_krb5_pac(smb_token_t *, char *, uint_t); +extern boolean_t smb_token_setup_common(smb_token_t *); + /* * The maximum number of domains (NT limit). diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers index 29af98f2ac..eece54e174 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2014 Nexenta Systems, Inc. All rights reserved. # # @@ -53,6 +54,7 @@ SYMBOL_VERSION SUNWprivate { mlsvc_netlogon; smb_autohome_add; smb_autohome_remove; + smb_decode_krb5_pac; smb_locate_dc; smb_logon; smb_logon_abort; @@ -76,6 +78,7 @@ SYMBOL_VERSION SUNWprivate { smb_shr_stop; smb_token_destroy; smb_token_log; + smb_token_setup_common; spoolss_register_copyfile; local: *; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c index 566837fe2d..a3fbb4d96f 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* @@ -61,6 +61,8 @@ static void netr_setup_identity(ndr_heap_t *, smb_logon_t *, static boolean_t netr_isadmin(struct netr_validation_info3 *); static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *, smb_ids_t *); +static uint32_t netr_setup_token_info3(struct netr_validation_info3 *, + smb_token_t *); static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *, smb_token_t *); @@ -75,6 +77,83 @@ static boolean_t netlogon_busy = B_FALSE; static boolean_t netlogon_abort = B_FALSE; /* + * Helper for Kerberos authentication + */ +uint32_t +smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len) +{ + struct krb5_validation_info info; + ndr_buf_t *nbuf; + uint32_t status = NT_STATUS_NO_MEMORY; + int rc; + + bzero(&info, sizeof (info)); + + /* Need to keep this until we're done with &info */ + nbuf = ndr_buf_init(&TYPEINFO(netr_interface)); + if (nbuf == NULL) + goto out; + + rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC, + NETR_OPNUM_decode_krb5_pac, data, len, &info); + if (rc != NDR_DRC_OK) { + status = RPC_NT_PROTOCOL_ERROR; + goto out; + } + + status = netr_setup_token_info3(&info.info3, token); + + /* Deal with the "resource groups"? */ + + +out: + if (nbuf != NULL) + ndr_buf_fini(nbuf); + + return (status); +} + +/* + * Code factored out of netr_setup_token() + */ +static uint32_t +netr_setup_token_info3(struct netr_validation_info3 *info3, + smb_token_t *token) +{ + smb_sid_t *domsid; + + domsid = (smb_sid_t *)info3->LogonDomainId; + + token->tkn_user.i_sid = smb_sid_splice(domsid, + info3->UserId); + if (token->tkn_user.i_sid == NULL) + goto errout; + + token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, + info3->PrimaryGroupId); + if (token->tkn_primary_grp.i_sid == NULL) + goto errout; + + if (info3->EffectiveName.str) { + token->tkn_account_name = + strdup((char *)info3->EffectiveName.str); + if (token->tkn_account_name == NULL) + goto errout; + } + + if (info3->LogonDomainName.str) { + token->tkn_domain_name = + strdup((char *)info3->LogonDomainName.str); + if (token->tkn_domain_name == NULL) + goto errout; + } + + return (netr_setup_token_wingrps(info3, token)); +errout: + return (NT_STATUS_INSUFF_SERVER_RESOURCES); +} + +/* * Abort impending domain logon requests. */ void @@ -254,13 +333,14 @@ netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info, * exclusively ored with the 16 byte UserSessionKey to recover * the the clear form. */ - if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) + if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) return (NT_STATUS_NO_MEMORY); + token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ; bzero(rc4key, SMBAUTH_SESSION_KEY_SZ); bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len); - bcopy(info3->UserSessionKey.data, token->tkn_session_key, + bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val, SMBAUTH_SESSION_KEY_SZ); - rand_hash((unsigned char *)token->tkn_session_key, + rand_hash((unsigned char *)token->tkn_ssnkey.val, SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ); return (NT_STATUS_SUCCESS); @@ -603,7 +683,14 @@ netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info, (void) mutex_unlock(&logon_id_mutex); - identity->parameter_control = 0; + /* + * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set + * ParameterControl to the 'E' + 'K' bits. Those are: + * (1 << 5) | (1 << 11), a.k.a + */ + identity->parameter_control = + MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | + MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; identity->logon_id.LowPart = logon_id; identity->logon_id.HighPart = 0; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c index 8ffc4f6f28..c9e634f515 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> @@ -82,6 +83,9 @@ smb_autohome_add(const smb_token_t *token) uid_t uid; gid_t gid; + if (token->tkn_flags & SMB_ATF_ANON) + return; + uid = token->tkn_user.i_id; gid = token->tkn_primary_grp.i_id; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c index 4b7a1cd178..24baa848e7 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <unistd.h> @@ -44,7 +45,6 @@ static rwlock_t smb_logoninit_rwl; typedef void (*smb_logonop_t)(smb_logon_t *, smb_token_t *); -extern void smb_logon_domain(smb_logon_t *, smb_token_t *); static void smb_logon_local(smb_logon_t *, smb_token_t *); static void smb_logon_guest(smb_logon_t *, smb_token_t *); static void smb_logon_anon(smb_logon_t *, smb_token_t *); @@ -158,8 +158,8 @@ smb_token_sids2ids(smb_token_t *token) } stat = smb_idmap_batch_getmappings(&sib); - smb_idmap_batch_destroy(&sib); smb_idmap_check("smb_idmap_batch_getmappings", stat); + smb_idmap_batch_destroy(&sib); return (stat == IDMAP_SUCCESS ? 0 : -1); } @@ -253,7 +253,7 @@ smb_token_destroy(smb_token_t *token) free(token->tkn_posix_grps); free(token->tkn_account_name); free(token->tkn_domain_name); - free(token->tkn_session_key); + free(token->tkn_ssnkey.val); bzero(token, sizeof (smb_token_t)); free(token); } @@ -344,8 +344,10 @@ smb_token_set_flags(smb_token_t *token) * has been done. * * Note that the order of calls in this function are important. + * + * Returns B_TRUE for success. */ -static boolean_t +boolean_t smb_token_setup_common(smb_token_t *token) { smb_token_set_flags(token); @@ -475,7 +477,6 @@ smb_logon_local(smb_logon_t *user_info, smb_token_t *token) char guest[SMB_USERNAME_MAXLEN]; smb_passwd_t smbpw; uint32_t status; - boolean_t isguest; if (user_info->lg_secmode == SMB_SECMODE_DOMAIN) { if ((user_info->lg_domain_type != SMB_DOMAIN_LOCAL) && @@ -483,16 +484,18 @@ smb_logon_local(smb_logon_t *user_info, smb_token_t *token) return; } + /* + * If the requested account name is "guest" (or whatever + * our guest account is named) then don't handle it here. + * Let this request fall through to smb_logon_guest(). + */ smb_guest_account(guest, SMB_USERNAME_MAXLEN); - isguest = (smb_strcasecmp(guest, user_info->lg_e_username, 0) == 0); + if (smb_strcasecmp(guest, user_info->lg_e_username, 0) == 0) + return; status = smb_token_auth_local(user_info, token, &smbpw); - if (status == NT_STATUS_SUCCESS) { - if (isguest) - status = smb_token_setup_guest(user_info, token); - else - status = smb_token_setup_local(&smbpw, token); - } + if (status == NT_STATUS_SUCCESS) + status = smb_token_setup_local(&smbpw, token); user_info->lg_status = status; } @@ -514,23 +517,31 @@ smb_logon_guest(smb_logon_t *user_info, smb_token_t *token) char guest[SMB_USERNAME_MAXLEN]; smb_passwd_t smbpw; char *temp; - uint32_t status; if (user_info->lg_status != NT_STATUS_NO_SUCH_USER) return; + /* Get the name of the guest account. */ smb_guest_account(guest, SMB_USERNAME_MAXLEN); - temp = user_info->lg_e_username; - user_info->lg_e_username = guest; - status = smb_token_auth_local(user_info, token, &smbpw); - if ((status == NT_STATUS_SUCCESS) || - (status == NT_STATUS_NO_SUCH_USER)) { - status = smb_token_setup_guest(user_info, token); - } + /* Does the guest account exist? */ + if (smb_pwd_getpwnam(guest, &smbpw) == NULL) + return; + /* Is it enabled? (empty p/w is OK) */ + if (smbpw.pw_flags & SMB_PWF_DISABLE) + return; + + /* + * OK, give the client a guest logon. Note that on entry, + * lg_e_username is typically something other than "guest" + * so we need to set the effective username when createing + * the guest token. + */ + temp = user_info->lg_e_username; + user_info->lg_e_username = guest; + user_info->lg_status = smb_token_setup_guest(user_info, token); user_info->lg_e_username = temp; - user_info->lg_status = status; } /* @@ -552,7 +563,7 @@ static uint32_t smb_token_auth_local(smb_logon_t *user_info, smb_token_t *token, smb_passwd_t *smbpw) { - boolean_t lm_ok, nt_ok; + boolean_t ok; uint32_t status = NT_STATUS_SUCCESS; if (smb_pwd_getpwnam(user_info->lg_e_username, smbpw) == NULL) @@ -561,41 +572,42 @@ smb_token_auth_local(smb_logon_t *user_info, smb_token_t *token, if (smbpw->pw_flags & SMB_PWF_DISABLE) return (NT_STATUS_ACCOUNT_DISABLED); - nt_ok = lm_ok = B_FALSE; - if ((smbpw->pw_flags & SMB_PWF_LM) && - (user_info->lg_lm_password.len != 0)) { - lm_ok = smb_auth_validate_lm( - user_info->lg_challenge_key.val, - user_info->lg_challenge_key.len, - smbpw, - user_info->lg_lm_password.val, - user_info->lg_lm_password.len, - user_info->lg_domain, - user_info->lg_username); - token->tkn_session_key = NULL; - } - - if (!lm_ok && (user_info->lg_nt_password.len != 0)) { - token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ); - if (token->tkn_session_key == NULL) - return (NT_STATUS_NO_MEMORY); - nt_ok = smb_auth_validate_nt( - user_info->lg_challenge_key.val, - user_info->lg_challenge_key.len, - smbpw, - user_info->lg_nt_password.val, - user_info->lg_nt_password.len, - user_info->lg_domain, - user_info->lg_username, - (uchar_t *)token->tkn_session_key); + if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT)) == 0) { + /* + * The SMB passwords have not been set. + * Return an error that suggests the + * password needs to be set. + */ + return (NT_STATUS_PASSWORD_EXPIRED); } - if (!nt_ok && !lm_ok) { - status = NT_STATUS_WRONG_PASSWORD; - syslog(LOG_NOTICE, "logon[%s\\%s]: %s", - user_info->lg_e_domain, user_info->lg_e_username, - xlate_nt_status(status)); - } + token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ); + if (token->tkn_ssnkey.val == NULL) + return (NT_STATUS_NO_MEMORY); + token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ; + + ok = smb_auth_validate( + smbpw, + user_info->lg_domain, + user_info->lg_username, + user_info->lg_challenge_key.val, + user_info->lg_challenge_key.len, + user_info->lg_nt_password.val, + user_info->lg_nt_password.len, + user_info->lg_lm_password.val, + user_info->lg_lm_password.len, + token->tkn_ssnkey.val); + if (ok) + return (NT_STATUS_SUCCESS); + + free(token->tkn_ssnkey.val); + token->tkn_ssnkey.val = NULL; + token->tkn_ssnkey.len = 0; + + status = NT_STATUS_WRONG_PASSWORD; + syslog(LOG_NOTICE, "logon[%s\\%s]: %s", + user_info->lg_e_domain, user_info->lg_e_username, + xlate_nt_status(status)); return (status); } diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com index 0c972a66f0..78dc4fdcfa 100644 --- a/usr/src/lib/smbsrv/libsmb/Makefile.com +++ b/usr/src/lib/smbsrv/libsmb/Makefile.com @@ -54,7 +54,6 @@ OBJS_COMMON = \ smb_info.o \ smb_kmod.o \ smb_lgrp.o \ - smb_mac.o \ smb_nic.o \ smb_pwdutil.o \ smb_privilege.o \ @@ -73,14 +72,16 @@ include ../../../Makefile.lib include ../../Makefile.lib INCS += -I$(SRC)/common/smbsrv +INCS += -I$(SRC)/lib/libsmbfs/smb LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2 LINTCHECKFLAGS += -erroff=E_BAD_FORMAT_STR2 LDLIBS += $(MACH_LDLIBS) +# perfer to keep libs ordered by dependence LDLIBS += -lscf -lmd -luuid -lpkcs11 -lcryptoutil -LDLIBS += -lsec -lidmap -lnsl -lsocket -lresolv -LDLIBS += -lreparse -lnvpair -lcmdutils -lavl -lc +LDLIBS += -lsec -lidmap -lreparse -lcmdutils -lavl +LDLIBS += -lnvpair -lresolv -lsocket -lnsl -lc CPPFLAGS += $(INCS) -D_REENTRANT CPPFLAGS += -Dsyslog=smb_syslog CERRWARN += -_gcc=-Wno-uninitialized diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h index 7c5f88976a..82bbe995c3 100644 --- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #ifndef _LIBSMB_H @@ -139,6 +139,7 @@ typedef enum { SMB_CI_DYNDNS_ENABLE, SMB_CI_MACHINE_PASSWD, + SMB_CI_MACHINE_UUID, SMB_CI_KPASSWD_SRV, SMB_CI_KPASSWD_DOMAIN, SMB_CI_KPASSWD_SEQNUM, @@ -193,6 +194,7 @@ extern boolean_t smb_config_get_ads_enable(void); extern int smb_config_get_debug(void); extern uint8_t smb_config_get_fg_flag(void); extern char *smb_config_get_localsid(void); +extern int smb_config_get_localuuid(uuid_t); extern int smb_config_secmode_fromstr(char *); extern char *smb_config_secmode_tostr(int); extern int smb_config_get_secmode(void); @@ -202,7 +204,7 @@ extern int smb_config_refresh_idmap(void); extern int smb_config_getip(smb_cfg_id_t, smb_inaddr_t *); extern void smb_config_get_version(smb_version_t *); uint32_t smb_config_get_execinfo(char *, char *, size_t); - +extern void smb_config_get_negtok(uchar_t *, uint32_t *); extern void smb_load_kconfig(smb_kmod_cfg_t *kcfg); extern uint32_t smb_crc_gen(uint8_t *, size_t); @@ -303,7 +305,7 @@ void libsmb_redirect_syslog(__FILE_TAG *fp, int priority); #define SMBAUTH_HASH_SZ 16 /* also LM/NTLM/NTLMv2 Hash size */ #define SMBAUTH_LM_RESP_SZ 24 /* also NTLM Response size */ #define SMBAUTH_LM_PWD_SZ 14 /* LM password size */ -#define SMBAUTH_V2_CLNT_CHALLENGE_SZ 8 /* both LMv2 and NTLMv2 */ +#define SMBAUTH_CHAL_SZ 8 /* both LMv2 and NTLMv2 */ #define SMBAUTH_SESSION_KEY_SZ SMBAUTH_HASH_SZ #define SMBAUTH_HEXHASH_SZ (SMBAUTH_HASH_SZ * 2) @@ -364,7 +366,7 @@ typedef struct smb_auth_data_blob { unsigned char ndb_signature[4]; unsigned char ndb_reserved[4]; uint64_t ndb_timestamp; - unsigned char ndb_clnt_challenge[SMBAUTH_V2_CLNT_CHALLENGE_SZ]; + unsigned char ndb_clnt_challenge[SMBAUTH_CHAL_SZ]; unsigned char ndb_unknown[4]; smb_auth_name_entry_t ndb_names[2]; unsigned char ndb_unknown2[4]; @@ -488,6 +490,9 @@ extern int smb_auth_RC4(unsigned char *, int, unsigned char *, int, extern int smb_auth_md4(unsigned char *, unsigned char *, int); extern int smb_auth_lm_hash(const char *, unsigned char *); extern int smb_auth_ntlm_hash(const char *, unsigned char *); +extern void smb_auth_ntlm2_mkchallenge(char *, const char *, const char *); +extern void smb_auth_ntlm2_kxkey(unsigned char *, const char *, const char *, + unsigned char *); extern int smb_auth_set_info(char *, char *, unsigned char *, char *, unsigned char *, @@ -496,12 +501,8 @@ extern int smb_auth_set_info(char *, char *, extern int smb_auth_ntlmv2_hash(unsigned char *, char *, char *, unsigned char *); -extern int smb_auth_gen_session_key(smb_auth_info_t *, unsigned char *); - -boolean_t smb_auth_validate_lm(unsigned char *, uint32_t, smb_passwd_t *, - unsigned char *, int, char *, char *); -boolean_t smb_auth_validate_nt(unsigned char *, uint32_t, smb_passwd_t *, - unsigned char *, int, char *, char *, uchar_t *); +boolean_t smb_auth_validate(smb_passwd_t *, char *, char *, + uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *); int smb_gen_random_passwd(char *passwd, size_t bufsz); @@ -516,14 +517,6 @@ extern void smb_ipc_rollback(void); extern void smb_ipc_set(char *, uint8_t *); /* - * SMB MAC Signing - */ - -#define SMB_MAC_KEY_SZ (SMBAUTH_SESSION_KEY_SZ + SMBAUTH_CS_MAXLEN) -#define SMB_SIG_OFFS 14 /* signature field offset within header */ -#define SMB_SIG_SIZE 8 /* SMB signature size */ - -/* * Signing flags: * * SMB_SCF_ENABLE Signing is enabled. @@ -547,38 +540,6 @@ extern void smb_ipc_set(char *, uint8_t *); #define SMB_SCF_KEY_ISSET_THIS_LOGON 0x08 /* - * smb_sign_ctx - * - * SMB signing context. - * - * ssc_seqnum sequence number - * ssc_keylen mac key length - * ssc_mid multiplex id - reserved - * ssc_flags flags - * ssc_mackey mac key - * ssc_sign mac signature - * - */ -typedef struct smb_sign_ctx { - unsigned int ssc_seqnum; - unsigned short ssc_keylen; - unsigned short ssc_mid; - unsigned int ssc_flags; - unsigned char ssc_mackey[SMB_MAC_KEY_SZ]; - unsigned char ssc_sign[SMB_SIG_SIZE]; -} smb_sign_ctx_t; - -extern int smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth); -extern int smb_mac_calc(smb_sign_ctx_t *sign_ctx, - const unsigned char *buf, size_t buf_len, unsigned char *mac_sign); -extern int smb_mac_chk(smb_sign_ctx_t *sign_ctx, - const unsigned char *buf, size_t buf_len); -extern int smb_mac_sign(smb_sign_ctx_t *sign_ctx, - unsigned char *buf, size_t buf_len); -extern void smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx); -extern void smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx); - -/* * Each domain is categorized using the enum values below. * The local domain refers to the local machine and is named * after the local hostname. The primary domain is the domain diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers index 3570d05ba4..c4c3814864 100644 --- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers @@ -75,13 +75,13 @@ SYMBOL_VERSION SUNWprivate { smb_acl_to_zfs; smb_auth_DES; smb_auth_RC4; - smb_auth_gen_session_key; smb_auth_hmac_md5; smb_auth_ntlm_hash; + smb_auth_ntlm2_kxkey; + smb_auth_ntlm2_mkchallenge; smb_auth_ntlmv2_hash; smb_auth_qnd_unicode; - smb_auth_validate_lm; - smb_auth_validate_nt; + smb_auth_validate; smb_buf32_xdr; smb_cache_add; smb_cache_create; @@ -265,11 +265,6 @@ SYMBOL_VERSION SUNWprivate { smb_logon_xdr; smb_lookup_name; smb_lookup_sid; - smb_mac_chk; - smb_mac_dec_seqnum; - smb_mac_inc_seqnum; - smb_mac_init; - smb_mac_sign; smb_match_netlogon_seqnum; smb_mbstos; smb_mbstowcs; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c index 9f4100e805..29918639e7 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c @@ -21,15 +21,70 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include <strings.h> #include <stdlib.h> +#include <syslog.h> +#include <sys/md5.h> #include <smbsrv/string.h> #include <smbsrv/libsmb.h> +#include <netsmb/spnego.h> /* libsmbfs */ #include <assert.h> +#define NTLM_CHAL_SZ SMBAUTH_CHAL_SZ /* challenge size */ + +/* + * Compute the combined (server+client) challenge per. [MS-NLMP 3.3.1] + * MD5(concat(ServerChallenge,ClientChallenge)) + */ +void +smb_auth_ntlm2_mkchallenge(char *result, + const char *srv_chal, const char *clnt_chal) +{ + MD5_CTX context; + uchar_t challenges[2 * NTLM_CHAL_SZ]; + uchar_t digest[SMBAUTH_HASH_SZ]; + + /* + * challenges = ConcatenationOf(ServerChallenge, ClientChallenge) + */ + (void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ); + (void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ); + + /* + * digest = MD5(challenges) + */ + MD5Init(&context); + MD5Update(&context, challenges, sizeof (challenges)); + MD5Final(digest, &context); + + /* + * result = digest[0..7] + */ + (void) memcpy(result, digest, NTLM_CHAL_SZ); +} + +void +smb_auth_ntlm2_kxkey(unsigned char *result, const char *srv_chal, + const char *clnt_chal, unsigned char *ssn_base_key) +{ + uchar_t challenges[2 * NTLM_CHAL_SZ]; + + /* + * challenges = ConcatenationOf(ServerChallenge, ClientChallenge) + */ + (void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ); + (void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ); + + /* HMAC_MD5(SessionBaseKey, concat(...)) */ + /* SMBAUTH_HMACT64 args: D, Dsz, K, Ksz, digest */ + (void) SMBAUTH_HMACT64(challenges, sizeof (challenges), + ssn_base_key, SMBAUTH_HASH_SZ, result); +} + /* * smb_auth_qnd_unicode * @@ -117,7 +172,7 @@ smb_auth_lm_hash(const char *password, unsigned char *lm_hash) */ static int smb_auth_lm_response(unsigned char *hash, - unsigned char *challenge, int clen, + unsigned char *challenge, /* NTLM_CHAL_SZ */ unsigned char *lm_rsp) { unsigned char S21[21]; @@ -131,7 +186,7 @@ smb_auth_lm_response(unsigned char *hash, /* padded LM Hash -> LM Response */ return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21, - challenge, clen)); + challenge, NTLM_CHAL_SZ)); } /* @@ -174,7 +229,7 @@ smb_auth_ntlm_hash(const char *password, unsigned char *hash) */ static int smb_auth_ntlm_response(unsigned char *hash, - unsigned char *challenge, int clen, + unsigned char *challenge, /* NTLM_CHAL_SZ */ unsigned char *ntlm_rsp) { unsigned char S21[21]; @@ -182,7 +237,7 @@ smb_auth_ntlm_response(unsigned char *hash, bcopy(hash, S21, SMBAUTH_HASH_SZ); bzero(&S21[SMBAUTH_HASH_SZ], 5); if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ, - S21, 21, challenge, clen) == SMBAUTH_FAILURE) + S21, 21, challenge, NTLM_CHAL_SZ) == SMBAUTH_FAILURE) return (0); return (SMBAUTH_LM_RESP_SZ); } @@ -253,13 +308,14 @@ smb_auth_ntlmv2_hash(unsigned char *ntlm_hash, static int smb_auth_v2_response( unsigned char *hash, - unsigned char *srv_challenge, int slen, + unsigned char *srv_challenge, /* NTLM_CHAL_SZ */ unsigned char *clnt_data, int clen, unsigned char *v2_rsp) { unsigned char *hmac_data; + int slen = NTLM_CHAL_SZ; - hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char)); + hmac_data = malloc(NTLM_CHAL_SZ + clen); if (!hmac_data) { return (-1); } @@ -275,70 +331,39 @@ smb_auth_v2_response( return (SMBAUTH_HASH_SZ + clen); } -/* - * smb_auth_gen_session_key - * - * Generate the NTLM user session key if LMCompatibilityLevel is 2 or - * NTLMv2 user session key if LMCompatibilityLevel is 3 or above. - * - * NTLM_Session_Key = MD4(NTLM_Hash); - * - * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16) - * - * Prior to calling this function, the auth instance should be set - * via smb_auth_set_info(). - * - * Returns the appropriate session key. - */ -int -smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key) -{ - int rc; - - if (auth->lmcompatibility_lvl == 2) - rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ); - else - rc = SMBAUTH_HMACT64((unsigned char *)auth->cs, - SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2, - SMBAUTH_SESSION_KEY_SZ, session_key); - - return (rc); -} static boolean_t smb_lm_password_ok( unsigned char *challenge, - uint32_t clen, unsigned char *lm_hash, - unsigned char *passwd) + unsigned char *lm_resp) { - unsigned char lm_resp[SMBAUTH_LM_RESP_SZ]; + unsigned char ok_resp[SMBAUTH_LM_RESP_SZ]; int rc; - rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp); + rc = smb_auth_lm_response(lm_hash, challenge, ok_resp); if (rc != SMBAUTH_SUCCESS) return (B_FALSE); - return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0); + return (bcmp(ok_resp, lm_resp, SMBAUTH_LM_RESP_SZ) == 0); } static boolean_t smb_ntlm_password_ok( unsigned char *challenge, - uint32_t clen, unsigned char *ntlm_hash, - unsigned char *passwd, + unsigned char *nt_resp, unsigned char *session_key) { - unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ]; + unsigned char ok_resp[SMBAUTH_LM_RESP_SZ]; int rc; boolean_t ok; - rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp); + rc = smb_auth_ntlm_response(ntlm_hash, challenge, ok_resp); if (rc != SMBAUTH_LM_RESP_SZ) return (B_FALSE); - ok = (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0); + ok = (bcmp(ok_resp, nt_resp, SMBAUTH_LM_RESP_SZ) == 0); if (ok && (session_key)) { rc = smb_auth_md4(session_key, ntlm_hash, SMBAUTH_HASH_SZ); if (rc != SMBAUTH_SUCCESS) @@ -350,7 +375,6 @@ smb_ntlm_password_ok( static boolean_t smb_ntlmv2_password_ok( unsigned char *challenge, - uint32_t clen, unsigned char *ntlm_hash, unsigned char *passwd, int pwdlen, @@ -404,7 +428,7 @@ smb_ntlmv2_password_ok( break; if (smb_auth_v2_response(ntlmv2_hash, challenge, - clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0) + clnt_blob, clnt_blob_len, ntlmv2_resp) < 0) break; ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0); @@ -426,8 +450,7 @@ smb_ntlmv2_password_ok( static boolean_t smb_lmv2_password_ok( - unsigned char *challenge, - uint32_t clen, + unsigned char *srv_challenge, unsigned char *ntlm_hash, unsigned char *passwd, char *domain, @@ -469,8 +492,8 @@ smb_lmv2_password_ok( ntlmv2_hash) != SMBAUTH_SUCCESS) break; - if (smb_auth_v2_response(ntlmv2_hash, challenge, - clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ, + if (smb_auth_v2_response(ntlmv2_hash, srv_challenge, + clnt_challenge, SMBAUTH_CHAL_SZ, lmv2_resp) < 0) break; @@ -484,81 +507,83 @@ smb_lmv2_password_ok( } /* - * smb_auth_validate_lm + * smb_auth_validate * - * Validates given LM/LMv2 client response, passed in passwd arg, against - * stored user's password, passed in smbpw - * - * If LM level <=3 server accepts LM responses, otherwise LMv2 + * Validates given NTLMv2 (or NTLM, LMv2, LM) client responses against + * the stored user's password, passed in smbpw. Try those in the order + * strongest to weakest, stopping at a point determined by the configured + * lmauth_level (LM Compatibility Level). */ boolean_t -smb_auth_validate_lm( - unsigned char *challenge, - uint32_t clen, +smb_auth_validate( smb_passwd_t *smbpw, - unsigned char *passwd, - int pwdlen, char *domain, - char *username) + char *username, + unsigned char *challenge, + uint_t clen, + unsigned char *nt_resp, + uint_t nt_len, + unsigned char *lm_resp, + uint_t lm_len, + uchar_t *session_key) { - boolean_t ok = B_FALSE; int64_t lmlevel; - - if (pwdlen != SMBAUTH_LM_RESP_SZ) - return (B_FALSE); + boolean_t ok = B_FALSE; if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK) return (B_FALSE); - if (lmlevel <= 3) { - ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash, - passwd); - } - - if (!ok) - ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash, - passwd, domain, username); + if (lmlevel > 5) + return (B_FALSE); - return (ok); -} + if (clen != NTLM_CHAL_SZ) + return (B_FALSE); -/* - * smb_auth_validate_nt - * - * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against - * stored user's password, passed in smbpw - * - * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2 - */ -boolean_t -smb_auth_validate_nt( - unsigned char *challenge, - uint32_t clen, - smb_passwd_t *smbpw, - unsigned char *passwd, - int pwdlen, - char *domain, - char *username, - uchar_t *session_key) -{ - int64_t lmlevel; - boolean_t ok; + /* + * Accept NTLMv2 at any LM level (0-5). + */ + if (nt_len > SMBAUTH_LM_RESP_SZ) { + ok = smb_ntlmv2_password_ok(challenge, + smbpw->pw_nthash, nt_resp, nt_len, + domain, username, session_key); + if (ok) + return (ok); + } - if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK) + if (lmlevel == 5) return (B_FALSE); - if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ)) + /* + * Accept NTLM at levels 0-4 + */ + if (nt_len == SMBAUTH_LM_RESP_SZ) { + ok = smb_ntlm_password_ok(challenge, smbpw->pw_nthash, + nt_resp, session_key); + if (ok) + return (ok); + } + + if (lmlevel == 4) return (B_FALSE); - if (pwdlen > SMBAUTH_LM_RESP_SZ) - ok = smb_ntlmv2_password_ok(challenge, clen, - smbpw->pw_nthash, passwd, pwdlen, - domain, username, session_key); - else - ok = smb_ntlm_password_ok(challenge, clen, - smbpw->pw_nthash, passwd, session_key); - return (ok); + /* + * Accept LM/LMv2 auth at levels 0-3 + */ + if (lm_len != SMBAUTH_LM_RESP_SZ) + return (B_FALSE); + if (session_key) + (void) smb_auth_md4(session_key, smbpw->pw_nthash, + SMBAUTH_HASH_SZ); + ok = smb_lmv2_password_ok(challenge, smbpw->pw_nthash, + lm_resp, domain, username); + if (ok) + return (ok); + ok = smb_lm_password_ok(challenge, smbpw->pw_lmhash, lm_resp); + if (ok) + return (ok); + + return (B_FALSE); } /* diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c index 08ab3376be..1110fd8792 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c @@ -58,6 +58,7 @@ typedef struct smb_cfg_param { /* idmap SMF fmri and Property Group */ #define IDMAP_FMRI_PREFIX "system/idmap" #define MACHINE_SID "machine_sid" +#define MACHINE_UUID "machine_uuid" #define IDMAP_DOMAIN "domain_name" #define IDMAP_PG_NAME "config" @@ -121,14 +122,12 @@ static smb_cfg_param_t smb_cfg_table[] = {SMB_CI_MACHINE_PASSWD, "machine_passwd", SCF_TYPE_ASTRING, SMB_CF_PROTECTED}, - {SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING, - 0}, - {SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING, - 0}, - {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, - 0}, - {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, - 0}, + + {SMB_CI_MACHINE_UUID, "machine_uuid", SCF_TYPE_ASTRING, 0}, + {SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING, 0}, + {SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING, 0}, + {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, 0}, + {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, 0}, {SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0}, {SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0}, {SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC}, @@ -136,6 +135,7 @@ static smb_cfg_param_t smb_cfg_table[] = {SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC}, {SMB_CI_DFS_STDROOT_NUM, "dfs_stdroot_num", SCF_TYPE_INTEGER, 0}, {SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0}, + /* SMB_CI_MAX */ }; @@ -800,7 +800,7 @@ smb_config_get_ads_enable(void) * * Returns value of the "config/machine_sid" parameter * from the IDMAP SMF configuration repository. - * + * Result is allocated; caller should free. */ char * smb_config_get_localsid(void) @@ -810,6 +810,32 @@ smb_config_get_localsid(void) } /* + * smb_config_get_localuuid + * + * Returns value of the "config/machine_uuid" parameter + * from the IDMAP SMF configuration repository. + * + */ +int +smb_config_get_localuuid(uuid_t uu) +{ + char *s; + + uuid_clear(uu); + s = smb_config_getenv_generic(MACHINE_UUID, IDMAP_FMRI_PREFIX, + IDMAP_PG_NAME); + if (s == NULL) + return (-1); + + if (uuid_parse(s, uu) < 0) { + free(s); + return (-1); + } + + return (0); +} + +/* * smb_config_set_idmap_domain * * Set the "config/domain_name" parameter from IDMAP SMF repository. diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_info.c b/usr/src/lib/smbsrv/libsmb/common/smb_info.c index ea6707951e..0dcae43179 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c @@ -20,11 +20,14 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ -#include <assert.h> #include <sys/types.h> +#include <sys/sockio.h> +#include <sys/socket.h> +#include <sys/utsname.h> + #include <stdarg.h> #include <unistd.h> #include <stdlib.h> @@ -39,11 +42,11 @@ #include <netinet/in.h> #include <arpa/nameser.h> #include <resolv.h> -#include <sys/sockio.h> -#include <sys/socket.h> + #include <smbsrv/smbinfo.h> #include <smbsrv/netbios.h> #include <smbsrv/libsmb.h> +#include <assert.h> static mutex_t seqnum_mtx; @@ -67,6 +70,7 @@ static rwlock_t smb_ipc_lock; void smb_load_kconfig(smb_kmod_cfg_t *kcfg) { + struct utsname uts; int64_t citem; bzero(kcfg, sizeof (smb_kmod_cfg_t)); @@ -106,6 +110,18 @@ smb_load_kconfig(smb_kmod_cfg_t *kcfg) sizeof (kcfg->skc_system_comment)); smb_config_get_version(&kcfg->skc_version); kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0); + if (smb_config_get_localuuid(kcfg->skc_machine_uuid) < 0) { + syslog(LOG_ERR, "smb_load_kconfig: no machine_uuid"); + uuid_generate_time(kcfg->skc_machine_uuid); + } + /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */ + + (void) uname(&uts); + (void) snprintf(kcfg->skc_native_os, sizeof (kcfg->skc_native_os), + "%s %s %s", uts.sysname, uts.release, uts.version); + + (void) strlcpy(kcfg->skc_native_lm, "Native SMB service", + sizeof (kcfg->skc_native_lm)); } /* diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c index 145d8da21c..8b7b32fb19 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c @@ -69,6 +69,7 @@ smb_kmod_isbound(void) return ((smbdrv_fd == -1) ? B_FALSE : B_TRUE); } +/* See also: smbsrv smb_server_store_cfg */ int smb_kmod_setcfg(smb_kmod_cfg_t *cfg) { @@ -83,13 +84,21 @@ smb_kmod_setcfg(smb_kmod_cfg_t *cfg) ioc.oplock_enable = cfg->skc_oplock_enable; ioc.sync_enable = cfg->skc_sync_enable; ioc.secmode = cfg->skc_secmode; - ioc.ipv6_enable = cfg->skc_ipv6_enable; ioc.netbios_enable = cfg->skc_netbios_enable; + ioc.ipv6_enable = cfg->skc_ipv6_enable; ioc.print_enable = cfg->skc_print_enable; ioc.traverse_mounts = cfg->skc_traverse_mounts; ioc.exec_flags = cfg->skc_execflags; + ioc.negtok_len = cfg->skc_negtok_len; ioc.version = cfg->skc_version; + (void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t)); + (void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok)); + (void) memcpy(ioc.native_os, cfg->skc_native_os, + sizeof (ioc.native_os)); + (void) memcpy(ioc.native_lm, cfg->skc_native_lm, + sizeof (ioc.native_lm)); + (void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain)); (void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn)); (void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname)); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_mac.c b/usr/src/lib/smbsrv/libsmb/common/smb_mac.c deleted file mode 100644 index 57fb74530c..0000000000 --- a/usr/src/lib/smbsrv/libsmb/common/smb_mac.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * SMB MAC Signing support. - */ - -#include <strings.h> -#include <security/cryptoki.h> -#include <security/pkcs11.h> - -#include <smbsrv/libsmb.h> - -#include <smbsrv/smb.h> - -/* - * smb_mac_init - * - * Calculates the MAC key using the specified user session - * key (NTLM or NTLMv2). - * - * Returns SMBAUTH_SUCCESS if key generation was successful, - * SMBAUTH_FAILURE if not. - */ -int -smb_mac_init(smb_sign_ctx_t *sign_ctx, smb_auth_info_t *auth) -{ - unsigned char S16[SMBAUTH_SESSION_KEY_SZ]; - - if (smb_auth_gen_session_key(auth, S16) != SMBAUTH_SUCCESS) - return (SMBAUTH_FAILURE); - bcopy(S16, sign_ctx->ssc_mackey, SMBAUTH_SESSION_KEY_SZ); - bcopy(auth->cs, &(sign_ctx->ssc_mackey[SMBAUTH_SESSION_KEY_SZ]), - auth->cs_len); - sign_ctx->ssc_keylen = SMBAUTH_SESSION_KEY_SZ + auth->cs_len; - return (SMBAUTH_SUCCESS); -} - -/* - * smb_mac_calc - * - * Calculates MAC signature for the given buffer and returns - * it in the mac_sign parameter. - * - * The MAC signature is calculated as follows: - * - * data = concat(MAC_Key, MAC_Key_Len, SMB_Msg, SMB_Msg_Len); - * hash = MD5(data); - * MAC = head(hash, 8); - * - * The tricky part is that a sequence number should be used - * in calculation instead of the signature field in the - * SMB header. - * - * Returns SMBAUTH_SUCCESS if cryptology framework use was successful, - * SMBAUTH_FAILURE if not. - */ -int -smb_mac_calc(smb_sign_ctx_t *sign_ctx, const unsigned char *buf, - size_t buf_len, unsigned char *mac_sign) -{ - CK_RV rv; - CK_MECHANISM mechanism; - CK_SESSION_HANDLE hSession; - unsigned long diglen = MD_DIGEST_LEN; - int rc = SMBAUTH_FAILURE; - - int offset_end_of_sig = (SMB_SIG_OFFS + SMB_SIG_SIZE); - unsigned char seq_buf[SMB_SIG_SIZE]; - unsigned char mac[16]; - - /* - * put seq_num into the first 4 bytes and - * zero out the next 4 bytes - */ - bcopy(&sign_ctx->ssc_seqnum, seq_buf, 4); - bzero(seq_buf + 4, 4); - - mechanism.mechanism = CKM_MD5; - mechanism.pParameter = 0; - mechanism.ulParameterLen = 0; - - rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); - if (rv != CKR_OK) - return (SMBAUTH_FAILURE); - - /* Initialize the digest operation in the session */ - rv = C_DigestInit(hSession, &mechanism); - if (rv != CKR_OK) - goto smbmacdone; - - /* init with the MAC key */ - rv = C_DigestUpdate(hSession, sign_ctx->ssc_mackey, - sign_ctx->ssc_keylen); - if (rv != CKR_OK) - goto smbmacdone; - - /* copy in SMB packet info till signature field */ - rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf, SMB_SIG_OFFS); - if (rv != CKR_OK) - goto smbmacdone; - - /* copy in the seq_buf instead of the signature */ - rv = C_DigestUpdate(hSession, seq_buf, sizeof (seq_buf)); - if (rv != CKR_OK) - goto smbmacdone; - - /* copy in the rest of the packet, skipping the signature */ - rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)buf + offset_end_of_sig, - buf_len - offset_end_of_sig); - if (rv != CKR_OK) - goto smbmacdone; - - rv = C_DigestFinal(hSession, mac, &diglen); - if (rv != CKR_OK) - goto smbmacdone; - - bcopy(mac, mac_sign, SMB_SIG_SIZE); - rc = SMBAUTH_SUCCESS; - -smbmacdone: - (void) C_CloseSession(hSession); - return (rc); -} - -/* - * smb_mac_chk - * - * Calculates MAC signature for the given buffer - * and compares it to the signature in the given context. - * Return 1 if the signature are match, otherwise, return (0); - */ -int -smb_mac_chk(smb_sign_ctx_t *sign_ctx, - const unsigned char *buf, size_t buf_len) -{ - unsigned char mac_sign[SMB_SIG_SIZE]; - - /* calculate mac signature */ - if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS) - return (0); - - /* compare the signatures */ - if (memcmp(sign_ctx->ssc_sign, mac_sign, SMB_SIG_SIZE) == 0) - return (1); - - return (0); -} - -/* - * smb_mac_sign - * - * Calculates MAC signature for the given buffer, - * and write it to the buffer's signature field. - * - * Returns SMBAUTH_SUCCESS if cryptology framework use was successful, - * SMBAUTH_FAILURE if not. - */ -int -smb_mac_sign(smb_sign_ctx_t *sign_ctx, unsigned char *buf, size_t buf_len) -{ - unsigned char mac_sign[SMB_SIG_SIZE]; - - /* calculate mac signature */ - if (smb_mac_calc(sign_ctx, buf, buf_len, mac_sign) != SMBAUTH_SUCCESS) - return (SMBAUTH_FAILURE); - - /* put mac signature in the header's signature field */ - (void) memcpy(buf + SMB_SIG_OFFS, mac_sign, SMB_SIG_SIZE); - return (SMBAUTH_SUCCESS); -} - -void -smb_mac_inc_seqnum(smb_sign_ctx_t *sign_ctx) -{ - sign_ctx->ssc_seqnum++; -} - -void -smb_mac_dec_seqnum(smb_sign_ctx_t *sign_ctx) -{ - sign_ctx->ssc_seqnum--; -} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c index b359d32d5d..19cb5166a1 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c @@ -21,6 +21,8 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include <syslog.h> @@ -262,10 +264,13 @@ smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw) return (smb_pwd_ops.pwop_getpwnam(name, smbpw)); err = smb_pwd_lock(); - if (err != SMB_PWE_SUCCESS) + if (err != SMB_PWE_SUCCESS) { + syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err); return (NULL); + } if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { + syslog(LOG_WARNING, "smb_pwdutil: open failed, %m"); (void) smb_pwd_unlock(); return (NULL); } @@ -274,8 +279,7 @@ smb_pwd_getpwnam(const char *name, smb_passwd_t *smbpw) while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) { if (strcmp(name, smbpw->pw_name) == 0) { - if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT))) - found = B_TRUE; + found = B_TRUE; break; } } @@ -311,10 +315,13 @@ smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw) return (smb_pwd_ops.pwop_getpwuid(uid, smbpw)); err = smb_pwd_lock(); - if (err != SMB_PWE_SUCCESS) + if (err != SMB_PWE_SUCCESS) { + syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", err); return (NULL); + } if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { + syslog(LOG_WARNING, "smb_pwdutil: open failed, %m"); (void) smb_pwd_unlock(); return (NULL); } @@ -323,8 +330,7 @@ smb_pwd_getpwuid(uid_t uid, smb_passwd_t *smbpw) while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) { if (uid == smbpw->pw_uid) { - if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT))) - found = B_TRUE; + found = B_TRUE; break; } } @@ -1002,10 +1008,13 @@ smb_lucache_do_update(void) void *cookie = NULL; FILE *fp; - if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) + if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) { + syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", rc); return (rc); + } if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { + syslog(LOG_WARNING, "smb_pwdutil: open failed, %m"); (void) smb_pwd_unlock(); return (SMB_PWE_OPEN_FAILED); } diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h index 279634afc2..d60bca8785 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMBSRV_SMB_KRB_H @@ -40,6 +41,7 @@ extern "C" { #define SMB_PN_SALT 0x0008 /* w/ REALM */ #define SMB_PN_SVC_HOST "host" +#define SMB_PN_SVC_CIFS "cifs" #define SMB_PN_SVC_NFS "nfs" #define SMB_PN_SVC_HTTP "HTTP" #define SMB_PN_SVC_ROOT "root" @@ -47,7 +49,11 @@ extern "C" { /* Assign an identifier for each principal name format */ typedef enum smb_krb5_pn_id { SMB_KRB5_PN_ID_SALT, - SMB_KRB5_PN_ID_HOST_FQHN, + SMB_KRB5_PN_ID_HOST_FQHN, /* fully qualified name */ + SMB_KRB5_PN_ID_HOST_SHORT, /* short name */ + SMB_KRB5_PN_ID_CIFS_FQHN, + SMB_KRB5_PN_ID_CIFS_SHORT, + SMB_KRB5_PN_ID_MACHINE, /* the machine account */ SMB_KRB5_PN_ID_NFS_FQHN, SMB_KRB5_PN_ID_HTTP_FQHN, SMB_KRB5_PN_ID_ROOT_FQHN, diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c index 946ca6461a..7a6a3491a1 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include <stdio.h> @@ -49,9 +50,17 @@ static smb_krb5_pn_t smb_krb5_pn_tab[] = { */ {SMB_KRB5_PN_ID_SALT, SMB_PN_SVC_HOST, SMB_PN_SALT}, - /* HOST */ + /* CIFS SPNs. (HOST, CIFS, ...) */ {SMB_KRB5_PN_ID_HOST_FQHN, SMB_PN_SVC_HOST, SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR | SMB_PN_UPN_ATTR}, + {SMB_KRB5_PN_ID_HOST_SHORT, SMB_PN_SVC_HOST, + SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR}, + {SMB_KRB5_PN_ID_CIFS_FQHN, SMB_PN_SVC_CIFS, + SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR}, + {SMB_KRB5_PN_ID_CIFS_SHORT, SMB_PN_SVC_CIFS, + SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR}, + {SMB_KRB5_PN_ID_MACHINE, NULL, + SMB_PN_KEYTAB_ENTRY}, /* NFS */ {SMB_KRB5_PN_ID_NFS_FQHN, SMB_PN_SVC_NFS, @@ -529,12 +538,30 @@ smb_krb5_get_pn_by_id(smb_krb5_pn_id_t id, uint32_t type, break; case SMB_KRB5_PN_ID_HOST_FQHN: + case SMB_KRB5_PN_ID_CIFS_FQHN: case SMB_KRB5_PN_ID_NFS_FQHN: case SMB_KRB5_PN_ID_HTTP_FQHN: case SMB_KRB5_PN_ID_ROOT_FQHN: (void) asprintf(&buf, "%s/%s.%s", pn->p_svc, hostname, fqdn); break; + + case SMB_KRB5_PN_ID_HOST_SHORT: + case SMB_KRB5_PN_ID_CIFS_SHORT: + (void) asprintf(&buf, "%s/%s", + pn->p_svc, nbname); + break; + + /* + * SPN for the machine account, which is simply the + * (short) machine name with a dollar sign appended. + */ + case SMB_KRB5_PN_ID_MACHINE: + (void) asprintf(&buf, "%s$", nbname); + break; + + default: + return (NULL); } /* |