root/usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c
/*
 * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
 */

/*
 * There used to be a "redirector" library, which has been replaced,
 * leaving only the "glue" functions in this file that adapt this
 * library to the interface provided by libsmbfs.
 */

#include <errno.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <priv.h>

#include <netsmb/smbfs_api.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <libsmbrdr.h>
#include <mlsvc.h>

#include <assert.h>

void
smbrdr_initialize(void)
{
        (void) smb_lib_init();
}

/*
 * mlsvc_disconnect
 *
 * Disconnects the session with given server.
 * The new conection manager is smart enough
 * so that we don't need this to do anything.
 */
/* ARGSUSED */
void
smbrdr_disconnect(const char *server)
{
}


/*
 * smbrdr_logon
 *
 * I'm not sure this really needs to do anything, but for now
 * let's go ahead and authenticate here so this can return a
 * status reflecting the outcome of authentication.
 *
 * If this successfully builds an smb_ctx, it just frees it.
 * The driver retains sessions for a little while after the
 * last reference goes away, so the session created here will
 * usually still exist when the next call to smbrdr_ctx_new
 * asks for this server+user (immediately after this returns),
 * and only one session setup will go over the wire.
 */
int
smbrdr_logon(char *srv, char *dom, char *user)
{
        struct smb_ctx *ctx;
        int err;

        err = smbrdr_ctx_new(&ctx, srv, dom, user);
        if (err == 0)
                smb_ctx_free(ctx);
        return (err);
}

void
smbrdr_ctx_free(struct smb_ctx *ctx)
{
        smb_ctx_free(ctx);
}

/*
 * Setup a new SMB client context.
 *
 * Get the SMB server's configuration stuff and
 * store it in the new client context object.
 */
int
smbrdr_ctx_new(struct smb_ctx **ctx_p, char *server,
        char *domain, char *user)
{
        struct smb_ctx *ctx = NULL;
        uchar_t nthash[SMBAUTH_HASH_SZ];
        int64_t lmcl;
        int authflags, err;

        assert(server != NULL);
        assert(domain != NULL);
        assert(user != NULL);

        if (server[0] == '\0')
                return (NT_STATUS_INTERNAL_ERROR);

        if ((err = smb_ctx_alloc(&ctx)) != 0)
                return (NT_STATUS_NO_MEMORY);

        /*
         * Set server, share, domain, user
         * (in the ctx handle).
         */
        (void) smb_ctx_setfullserver(ctx, server);
        (void) smb_ctx_setshare(ctx, "IPC$", USE_IPC);
        (void) smb_ctx_setdomain(ctx, domain, B_TRUE);
        (void) smb_ctx_setuser(ctx, user, B_TRUE);

        /*
         * Set auth. info (hash) and type.
         */
        if (user[0] == '\0') {
                authflags = SMB_AT_ANON;
        } else {
                (void) smb_config_getnum(SMB_CI_LM_LEVEL, &lmcl);
                if (lmcl <= 2) {
                        /* Send NTLM */
                        authflags = SMB_AT_NTLM1;
                } else {
                        /* Send NTLMv2 */
                        authflags = SMB_AT_NTLM2;
                }
                smb_ipc_get_passwd(nthash, sizeof (nthash));
                (void) smb_ctx_setpwhash(ctx, nthash, NULL);
        }
        (void) smb_ctx_setauthflags(ctx, authflags);

        /*
         * Do lookup, connect, session setup, tree connect.
         * Or find and reuse a session/tree, if one exists.
         */
        if ((err = smb_ctx_resolve(ctx)) != 0) {
                err = NT_STATUS_BAD_NETWORK_PATH;
                goto errout;
        }
        if ((err = smb_ctx_get_ssn(ctx)) != 0) {
                switch (err) {
                case EAUTH:
                        err = NT_STATUS_NETWORK_ACCESS_DENIED;
                        break;
                default:
                        err = NT_STATUS_BAD_NETWORK_PATH;
                        break;
                }
                goto errout;
        }
        if ((err = smb_ctx_get_tree(ctx)) != 0) {
                err = NT_STATUS_BAD_NETWORK_NAME;
                goto errout;
        }

        /* Success! */
        *ctx_p = ctx;
        return (0);

errout:
        smb_ctx_free(ctx);
        return (err);
}