/*
* 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
* 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 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Authentication support for SMB session setup
*/
#include <sys/priv_names.h>
#include <smbsrv/smb_idmap.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_token.h>
/* void smb_authsock_close(smb_user_t *); kproto.h */
/*
* Handle old-style session setup (non-extended security)
*
* The user information is passed to smbd for authentication.
* If smbd can authenticate the user an access token is returned and we
* generate a cred and new user based on the token.
*/
int
{
return (NT_STATUS_TOO_MANY_SESSIONS);
/* user cleanup in smb_request_free */
/*
* Open a connection to the local logon service.
* If we can't, it may be busy, or not running.
* Don't log here - this may be frequent.
*/
goto errout;
/*
* Tell the auth. svc who this client is.
*/
goto errout;
/*
* Authentication proper
*/
goto errout;
/*
* Get the final auth. token.
*/
goto errout;
return (0);
return (status);
}
/*
* Build an authentication request message and
* send it to the local logon service.
*/
static uint32_t
{
/* lg_flags? */
xdr_destroy(&xdrs);
if (!ok) {
goto out;
}
if (status != 0)
goto out;
/*
* Decode the response message.
*/
switch (msg_hdr.lmh_msgtype) {
case LSA_MTYPE_OK:
status = 0;
break;
case LSA_MTYPE_ERROR:
if (rlen == sizeof (smb_lsa_eresp_t)) {
break;
}
/* FALLTHROUGH */
default: /* Bogus message type */
break;
}
out:
return (status);
}
/*
* Handle new-style (extended security) session setup.
* Returns zero: success, non-zero: error (value not used)
*
* Note that this style uses a sequence of session setup requests,
* where the first has SMB UID=0, and subsequent requests in the
* same authentication sequence have the SMB UID returned for that
* first request. We allocate a USER object when the first request
* in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that
* to maintain state between requests in this sequence. The state
* for one sequence includes an AF_UNIX "authsock" connection to the
* user-space smbd. The neat part of this is: in smbd, the handler
* for the server-side of one authsock gets only request specific to
* one authentication sequence, simplifying it's work immensely.
* When the authentication sequence is finished, with either success
* or failure, the local side of the authsock is closed.
*
* As with the old-style authentication, if we succeed, then the
* last message from smbd will be an smb_token_t encoding the
* information about the new user.
*
* Outline:
* (a) On the first request (UID==0) create a USER object,
* and on subsequent requests, find USER by SMB UID.
* (b) Send message / recv. response as above,
* (c) If response says "we're done", close authsock
* (both success and failure must close authsock)
*/
int
{
/*
* On the first request (UID==0) create a USER object.
* On subsequent requests (UID!=0) find the USER object.
* Either way, sr->uid_user is set, so our ref. on the
* user object is dropped during normal cleanup work
* for the smb_request (sr). Ditto u_authsock.
*/
return (NT_STATUS_TOO_MANY_SESSIONS);
/* user cleanup in smb_request_free */
/*
* Open a connection to the local logon service.
* If we can't, it may be busy, or not running.
* Don't log here - this may be frequent.
*/
goto errout;
/*
* Tell the auth. svc who this client is.
*/
goto errout;
} else {
return (NT_STATUS_USER_SESSION_DELETED);
/* user cleanup in smb_request_free */
}
/*
* Wrap the "security blob" with our header
* (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT)
* and send it up the authsock with either
*/
if (status != 0)
goto errout;
/*
* Decode the response message.
* Note: allocated rbuf
*/
switch (msg_hdr.lmh_msgtype) {
case LSA_MTYPE_ES_CONT:
/*
* This is not really an error, but tells the client
* it should send another session setup request.
*/
break;
case LSA_MTYPE_ES_DONE:
sinfo->ssi_ntpwlen = 0;
/*
* Get the final auth. token.
*/
break;
case LSA_MTYPE_ERROR:
/*
* Authentication failed. Return the error
* provided in the reply message.
*/
if (rlen == sizeof (smb_lsa_eresp_t)) {
goto errout;
}
/* FALLTHROUGH */
default: /* Bogus message type */
goto errout;
}
}
return (status);
}
/*
* Send the "client info" up to the auth service.
*/
static uint32_t
{
/*
* Send a message with info. about the client
* (IP address, etc) and wait for an ACK.
*/
sizeof (clinfo.lci_challenge_key));
/* We don't use this response. */
}
return (status);
}
/*
* After a successful authentication, ask the authsvc to
* send us the authentication token.
*/
static uint32_t
{
int rc;
msg_hdr.lmh_msglen = 0;
if (status != 0)
goto errout;
switch (msg_hdr.lmh_msgtype) {
case LSA_MTYPE_TOKEN:
status = 0;
break;
case LSA_MTYPE_ERROR:
if (rlen == sizeof (smb_lsa_eresp_t)) {
goto errout;
}
/* FALLTHROUGH */
default:
goto errout;
}
/*
* Authenticated. Decode the LSA_MTYPE_TOKEN.
*/
xdr_destroy(&xdrs);
if (!ok) {
goto errout;
}
/*
* Setup the logon object.
*/
goto errout;
/*
* Save the session key, and (maybe) enable signing,
* but only for real logon (not ANON or GUEST).
*/
} else {
}
if (rc != 0) {
goto errout;
}
}
return (0);
return (status);
}
/*
* Tokens are allocated in the kernel via XDR.
* Call xdr_free before freeing the token structure.
*/
void
{
}
}
/*
* Convert access token privileges to local definitions.
*/
static uint32_t
{
return (privileges);
}
/*
* Returns zero or an NT status.
*
* Errors here mean we can't communicate with the smbd_authsvc.
* With limited authsock instances, this should be rare.
*/
static uint32_t
{
int rc;
/*
* Get a hold on the auth socket.
*/
return (NT_STATUS_INTERNAL_ERROR);
}
}
if (rc)
goto out;
if (rc) {
}
}
out:
switch (rc) {
case 0:
status = 0;
break;
case EIO:
break;
case ENOTCONN:
break;
default:
break;
}
return (status);
}
/*
* Hope this is interpreted per-zone...
*/
/*
* Limit how long smb_authsock_sendrecv() will wait for a
* response from the local authentication service.
*/
/*
* Also limit the time smb_authsock_sendrecv() will wait
* trying to send a request to the authentication service.
*/
static uint32_t
{
int rc;
/*
* If the auth. service is busy, wait our turn.
* This may be frequent, so don't log.
*/
return (NT_STATUS_NO_LOGON_SERVERS);
KSOCKET_SLEEP, CRED());
if (rc != 0) {
goto errout;
}
/*
*/
/*
* Connect to the smbd auth. service.
*
* Would like to set the connect timeout too, but there's
* apparently no easy way to do that for AF_UNIX.
*/
sizeof (smbauth_sockname), CRED());
if (rc != 0) {
goto errout;
}
/* Note: u_authsock cleanup in smb_authsock_close() */
goto errout;
}
return (0);
return (status);
}
static int
{
int rc;
}
if (rc != 0) {
}
return (rc);
}
static int
{
int rc;
if (rc == 0) {
if (iocnt == 0) {
/* Should not happen with MSG_WAITALL */
}
}
if (rc != 0) {
}
return (rc);
}
void
{
return;
}