/*
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
*/
#include <sys/byteorder.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <libintl.h>
#include <assert.h>
#include <nss_dbdefs.h>
#include "smbfs_lib.h"
#include "smbfs_nb_lib.h"
#include "smbfs_charsets.h"
#include "smbfs_private.h"
#include "smbfs_ntlm.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#endif
struct nv {
char *name;
int value;
};
/* These two may be set by commands. */
int smbfs_debug;
/*
* Defaults for new contexts (connections to servers).
* These are set by smbfs_set_default_...
*/
/*
* Give the RPC library a callback hook that will be
* called whenever we destroy or reinit an smb_ctx_t.
* [The legacy name is rpc_cleanup_smbctx(), and was
* originally a direct call into the RPC code.]
*/
static void
{
if (close_hook)
(*close_hook)(ctx);
}
int
{
int err;
return (ENOMEM);
if (err != 0) {
return (err);
}
return (0);
}
/*
* Get configurations from SMF.
*
* The LM authentication levels are shown in the table below.
*
* To enable Kerberos authentication, Kerberos flag is always set with all LM
* compatibility levels during SMB context initialization.
*
* Client Server
* +---+------------------------------+-----------------------------+
* | 1 | Uses LM and NTLM | Accepts LM, NTLM and NTLMv2 |
* | | authentication | authentication |
* +---+------------------------------+-----------------------------+
* | 2 | Uses NTLM authentication | Accepts LM, NTLM and NTLMv2 |
* | | | authentication |
* +---+------------------------------+-----------------------------+
* | 3 | Uses NTLMv2 authentication | Accepts LM, NTLM and NTLMv2 |
* | | | authentication |
* +---+------------------------------+-----------------------------+
* | 4 | Uses NTLMv2 authentication | Accepts NTLM and NTLMv2 |
* | | | authentication |
* +---+------------------------------+-----------------------------+
* | 5 | Uses NTLMv2 authentication | Accepts NTLMv2 |
* | | | authentication |
* +---+------------------------------+-----------------------------+
*/
static void
{
switch (lmlevel) {
case 1:
ctx->ct_authflags =
break;
case 2:
break;
case 3:
case 4:
case 5:
break;
default:
/* no change from default: SMB_AT_DEFAULT */
break;
}
}
sizeof (domain));
if (*domain != '\0')
}
/*
* Initialize an smb_ctx struct (defaults)
*
* By default, SMB signing is enabled but not require.
*/
int
{
int error;
if (error)
return (error);
/* Fill in defaults */
/*
* Default domain, user, ...
*/
if (*default_domain != '\0')
return (0);
}
void
{
return;
}
void
{
}
}
}
if (ctx->ct_srvaddr_s) {
}
}
if (ctx->ct_locname) {
}
if (ctx->ct_origshare) {
}
if (ctx->ct_fullserver) {
}
if (ctx->ct_addrinfo) {
}
}
}
}
}
/*
* Parse the UNC path. Here we expect something like
* "//host[/share[/path]]"
*/
int
const char **next)
{
char *p;
int error;
/*
* This may be called outside of _scan_argv,
* so make sure these get initialized.
*/
/* Work on a temporary copy, fix back slashes. */
for (p = tmp; *p; p++)
if (*p == '\\')
*p = '/';
"UNC should start with '//'"), 0);
goto out;
}
p = tmp + 2;
/* Find the share part, if any. */
if (share)
*share = '\0';
(void) smbfs_unpercent(p); /* host component */
host = p;
if (*host == '\0') {
goto out;
}
if (error)
goto out;
if (share) {
/* restore the slash */
*share = '/';
p = share + 1;
/* Find the path part, if any. */
if (path)
*path = '\0';
(void) smbfs_unpercent(p); /* share component */
if (*p == '\0') {
"empty share name"), 0);
goto out;
}
"no share name required"), 0);
goto out;
}
/*
* Special case UNC names like:
* to have share: IPC$
*/
if (0 == strcasecmp(p, "PIPE")) {
p = "IPC$";
}
if (error)
goto out;
if (path) {
/* restore the slash */
*path = '/';
p = path + 1;
(void) smbfs_unpercent(p); /* remainder */
}
goto out;
}
if (next)
out:
if (error == 0 && smbfs_debug > 0)
return (error);
}
/*
* Parse the string: domuser, which may be any of:
* and return pointers to the domain and user parts.
* Modifies the string domuser in-place. Returned
* string pointers are within the string domusr.
*/
int
{
if (p == NULL) {
/* No separators - whole string is the user. */
return (0);
}
/* Have two strings. */
sc = *p; /* Save the sep. char */
*p++ = '\0'; /* zap it */
s2 = p;
/* Enforce just one separator */
if (p)
return (-1);
/*
* Now, which order are they?
*/
if (sc == '@') {
} else {
}
return (0);
}
int
{
return (0);
}
int
{
if (p == NULL)
return (ENOMEM);
if (ctx->ct_fullserver)
ctx->ct_fullserver = p;
return (0);
}
int
{
sizeof (ctx->ct_srvname));
return (0);
}
int
{
"user name '%s' too long"), 0, name);
return (ENAMETOOLONG);
}
/*
* Don't overwrite a value from the command line
* with one from anywhere else.
*/
return (0);
/* Mark this as "from the command line". */
if (from_cmd)
return (0);
}
/*
* Realm is obtained by converting the domain name to uppercase.
* Set realm by getting domain name from the resolver if either the full DNS
* domain name or the first label of the DNS domain name matches the passed
* name.
*/
int
{
return (-1);
return (-1);
*p = '\0';
return (0);
}
}
return (0);
}
/*
* Don't overwrite a domain name from the
* command line with one from anywhere else.
* See smbfs_ctx_init() for notes about this.
*/
int
{
"workgroup name '%s' too long"), 0, name);
return (ENAMETOOLONG);
}
/*
* Don't overwrite a value from the command line
* with one from anywhere else.
*/
return (0);
/* Mark this as "from the command line". */
if (from_cmd)
return (0);
}
int
{
int err;
return (EINVAL);
return (ENAMETOOLONG);
}
/*
* If called again after comand line parsing,
* don't overwrite a value from the command line
* with one from any stored config.
*/
return (0);
else
sizeof (ctx->ct_password));
/*
* Compute LM hash, NT hash.
*/
if (ctx->ct_password[0]) {
ctx->ct_password);
if (err != 0)
return (err);
ctx->ct_password);
if (err != 0)
return (err);
}
/* Mark this as "from the command line". */
if (from_cmd)
return (0);
}
/*
* Use this to set NTLM auth. info (hashes)
* when we don't have the password.
*/
int
{
/* Need ct_password to be non-null. */
sizeof (ctx->ct_password));
/* The LM hash is optional */
if (lmhash)
return (0);
}
int
{
"share name '%s' too long"), 0, share);
return (ENAMETOOLONG);
}
if (ctx->ct_origshare)
return (ENOMEM);
return (0);
}
/*
*/
int
{
if (required)
else
return (0);
}
/*
* Returns an EAI_xxx error number like getaddrinfo(3)
*/
static int
{
char *srvaddr_str;
return (EAI_NONAME);
}
/*
* If the user specified an address, use it,
* and don't do NetBIOS lookup.
*/
if (ctx->ct_srvaddr_s) {
} else
/*
* Default the server name we'll use in the
* protocol (i.e. NTLM, tree connect).
*/
sizeof (ctx->ct_srvname));
/*
* Try to lookup the host address using the
* normal name-to-IP address mechanisms.
* If that fails, we MAY try NetBIOS.
*/
if (gaierr == 0) {
return (0);
}
/*
* If regular IP name lookup failed, try NetBIOS,
* but only if given a valid NetBIOS name and if
* NetBIOS name lookup is enabled.
*/
if (gaierr2 == 0) {
if (res->ai_canonname)
sizeof (ctx->ct_srvname));
return (0);
}
}
/*
* Return the original error from getaddrinfo
*/
if (smbfs_debug) {
"getaddrinfo: %s: %s"), 0,
}
return (gaierr);
}
/*
* Verify context info. before connect operation(s),
* lookup specified server and try to fill all forgotten fields.
* Legacy name used by commands.
*/
int
{
int error = 0;
if (smbfs_debug)
"no server name specified"), 0);
return (EINVAL);
}
"no share name specified for %s@%s"),
return (EINVAL);
}
if (error)
return (error);
/*
* Lookup the IP address and fill in ct_addrinfo.
*
* Note: smbfs_ctx_getaddr() returns a EAI_xxx
* error value like getaddrinfo(3), but this
* function needs to return an errno value.
*/
if (error) {
"can't resolve name \"%s\", %s"),
return (ENODATA);
}
/*
* If we have a user name but no password,
* check for a keychain entry.
* XXX: Only for auth NTLM?
*/
/*
* No user name (anonymous session).
*/
} else {
/*
* Have a user name.
* If we don't have a p/w yet,
* try the keychain.
*/
(void) smbfs_get_keychain(ctx);
}
if (ctx->ct_authflags == 0) {
"no valid auth. types"), 0);
return (ENOTSUP);
}
if (smbfs_debug)
return (0);
}
int
{
int fd;
if (fd < 0) {
return (-1);
}
/* This handle controls per-process resources. */
return (fd);
}
int
{
}
fd = smbfs_open_driver();
if (fd < 0) {
"failed to open driver"), err);
return (err);
}
/*
* Check the driver version (paranoia)
*/
version = 0;
if (version != NSMB_VERSION) {
"incorrect driver version"), 0);
return (ENODEV);
}
return (0);
}
/*
* Find or create a connection + logon session
*/
int
{
int err = 0;
return (EINVAL);
return (err);
}
/*
* Check whether the driver already has a VC
* we can use. If so, we're done!
*/
if (err == 0) {
DPRINT("found an existing VC");
} else {
/*
* This calls the IOD to create a new session.
*/
DPRINT("setup a new VC");
if (err != 0)
return (err);
/*
* Call findvc again. The new VC sould be
* found in the driver this time.
*/
}
return (err);
}
/*
* Find or create a tree connection
*/
int
{
return (EINVAL);
}
return (ENOMEM);
/* The share name */
/* The share "use" type. */
/*
* Todo: share passwords for share-level security.
*
* The driver does the actual TCON call.
*/
goto out;
}
/*
* Check the returned share type
*/
"%s: incompatible share type"),
0, ctx->ct_origshare);
}
out:
return (err);
}
/*
* Return the hflags2 word for an smb_ctx.
*/
int
{
"can't get flags2 for a session"), errno);
return (-1);
}
return (flags2);
}
/*
* Get the transport level session key.
* Must already have an active SMB session.
*/
int
{
if (len < SMBIOC_HASH_SZ)
return (EINVAL);
return (errno);
return (0);
}
void
{
}
void
{
}
#pragma init(libsmbfs_init)
void
libsmbfs_init(void)
{
/*
* if the user name is not specified some other way,
* use the current user name (built-in default)
*/
}
/*
* Leave default domain empty. (That's valid).
*/
}
/*
* API for seting NetBIOS name lookup flags:
* NetBIOS name lookup enable,
* NetBIOS broadcast enable.
* Currently this APIs is unused.
*/
int
{
return (EINVAL);
return (0);
}
/*
* API for library consumer to set wins1, wins2
*/
int
{
return (EINVAL);
}
/*
* API for library consumer to set NB scope.
*/
int
{
return (EINVAL);
}