CIFS Client Design Document


Last revised: Jan 8, 2008


Table of contents

1 Introduction

    1.1 Purpose of Document
    1.2 Document's intended audience
    1.3 Document References
    1.4 Definitions of important terms, acronyms, or abbreviations
    1.5 Summary/Abstract of document contents

2 Project Overview

    2.1 What is CIFS?
    2.2 The user experience

    2.2.1 Browsing
    2.2.2 Mounting
    2.2.3 Nautilus
    2.2.4 Behavioral differences of filesystem commands

    2.3 High level Design diagram

3 Deliverables

    3.1 User Space commands/libraries

    3.1.1 smbutil
    3.1.2 mount_smbfs
    3.1.3 libsmbfs.so
    3.1.4 Changes to sharectl(1M)

    3.2 Kernel modules

    3.2.1 smbfs
    3.2.2 netsmb

    3.3 Binary list

    3.4 Areas of Overlap

    3.5 Other changes

4 Interfaces

    4.1 Exported interfaces
    4.2 Imported interfaces

5 Design Considerations

    5.1 Assumptions and Dependencies
    5.2 Goals and Guidelines
    5.3 Development Methods

    5.3.1 Description of methodology
    5.3.2 Comparison of Solaris and Darwin interfaces
    5.3.3 Re-use and adaptation of existing Solaris code
    5.3.4 Porting existing Darwin smbfs code
    5.3.5 Debugging via Tracing input and output on the wire

6 Security Considerations

    6.1 Authentication

    6.1.1 Anonymous and Guest login
    6.1.2 Plaintext passwords
    6.1.3 LM Challenge / Response
    6.1.4 NTLM Challenge / Response
    6.1.5 NTLMv2
    6.1.6 Extended Security and Kerberos

    6.2 Multi-user mounts
    6.3 RBAC and privileges
    6.4 Name Resolution
    6.5 Unattended Access

7 Architectural Strategies

    7.1 Use of smb-217.2 from Darwin
    7.2 Use of PSARC/2005/446 interfaces (uconv functions) which implement codeset conversion
    7.3 Use of nfsv2 vfsops and vnops code as a re-engineering base
    7.4 Error detection and recovery
    7.5 Memory management policies

    7.5.1 Memory allocation
    7.5.2 Mbufs vs. mblocks

    7.6 Concurrency and synchronization

    7.6.1 Threading
    7.6.2 Thread synchronization primitives
    7.6.3 Timers
    7.6.4 Concurrent access issues
    7.6.5 TIMEOUT support on the port

    7.7 Communication mechanisms

    7.7.1 Kernel authorization
    7.7.2 Byte ordering

    7.8 Other topics

    7.8.1 UIO routines
    7.8.2 vfs_context_t
    7.8.3 Codeset conversions
    7.8.4 Zones

    7.8.4.1 Conversion checklist
    7.8.4.2 Notes on the netsmb module
    7.8.4.3 Notes on the smbfs module

8 Detailed System Design

    8.1 smbutil

    8.1.1 Purpose
    8.1.2 Interfaces

    8.2 mount_smbfs

    8.2.1 Purpose
    8.2.2 Interfaces

    8.3 libsmbfs.so

    8.3.1 Purpose
    8.3.2 Interfaces
    8.3.3 RAP

    8.3.3.1 RPC (Remote Procedure Call) Protocol
    8.3.3.2 RAP (Remote Administration Protocol)

    8.4 smbfs

    8.4.1 Purpose
    8.4.2 Interfaces

    8.4.2.1 vfsops
    8.4.2.2 vnodeops

    8.5 netsmb

    8.5.1 Purpose
    8.5.2 Interfaces

    8.5.2.1 ioctl()'s available from device driver
    8.5.2.2 Interfaces exported to smbfs module
    8.5.2.3 Interface to networking code

    8.5.3 Consumers of the NetSMB module

9 Acknowledgements




1. Introduction

1.1 Purpose of Document

This document will contain all the information required to design and develop a CIFS client on Solaris. The reader will be able to get a high level understanding of the technical and organizational difficulties involved in creating the client and their proposed resolutions.

1.2 Document's intended audience

The intended audience includes the PSARC review team, the OpenSolaris user community, our Quality Engineering staff and our Technical Writing staff.

1.3 Document References

Requirements: http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/cifs_client_prd.html

1.4 Definitions of important terms, acronyms, or abbreviations

Terminal

Definition

SMB

Server Message Block - a network protocol mainly used by Microsoft Windows computers

CIFS

Common Internet File System - What SMB was renamed to by Microsoft in 1998

BSD

Berkeley Software Distribution - Any Unix derived from a distribution by the University of California, Berkeley, in the 1970s

RPC

Remote procedure call – A protocol allowing one host to call procedures on another.

RAP

Remote Administration Protocol – A Microsoft protocol allowing remote computer access.

ACL

Access control list – A list whose criteria provide controlled access to computer files.

IDL

Interface description language – A language that defines interfaces.

DES

Data Encryption Standard, a method of encryption.

NTLM

NT LAN Manager – Old name for a Microsoft computer networking security protocol now known as Integrated Windows Authentication (IWA)

UCS-2

Fixed-length (16 bits) subset of UTF-16, able to represent the basic multilingual plane only

cp437

Code page 437 - the original character set of the IBM PC, circa 1981

UTF-8

8-bit Unicode Transformation Format

UTF-16

16-bit Unicode Transformation Format

NetBIOS

Network Basic Input/Output System – A networking protocol originally developed for small networks.

TCP

Transmission Control Protocol – A core internet protocol allowing computers to exchange packets.

DCE

Distributed Computing Environment, a specification from The Open Group

SPNEGO

Simple and Protected GSSAPI Negotiation Mechanism

GSSAPI

Generic Security Services Application Program Interface

1.5 Summary/Abstract of document contents

This document describes the scope of this project, which is to deliver a standard virtual file system on the Solaris OS by designing a CIFS client that accesses files and directories on a CIFS server. Specifically, the document describes the user experience, the architecture, the design, the technical problems and resolutions, and the deliverables for the project.



2 Project Overview

This project will deliver a standard Solaris virtual file system which implements a CIFS client, providing access to files and directories on CIFS servers. The implementation on Solaris will be the result of a port from the smb version 217.2 package on Darwin 8.2, Darwin being a BSD variant underpinning MacOS X. A relatively large range of basic CIFS functionality is included in this code, so the main task is to get it ported to Solaris and running well. The Darwin package smb-217.2 has had an Open Source Code Review.

2.1 What is CIFS?

The CIFS protocol (Common Internet File System, a.k.a. SMB) is the natural file sharing protocol on Microsoft Windows machines, and is implemented by Samba on Unix/Linux. Using a CIFS client, users can mount remote CIFS server shares (directories) to get read-write access to previously inaccessible files.

2.2 The user experience

A user wishing to use CIFS shares should normally find the packages SUNWsmbfsr and SUNWsmbfsu installed in their default package cluster.

There are 2 user scenarios that describe the CIFS client user model:

1. Browsing shares on a Windows/CIFS server

2. Mounting one or more shares for direct access through standard Solaris file utilities, like 'ls', 'cat', 'vi', etc.

2.2.1 Browsing

The user would use the new 'smbutil(1)' binary to browse shares on a CIFS server as follows:

% smbutil view //[<workgroup>;][<user>[:<password>]@]<server>

For example, browsing the shares on server 'nano':


bash-3.00# smbutil view //root@nano 
Password: 
Share       Type        Comment 
------------------------------- 
ipc$        IPC         IPC Service (Samba Server) 
tmp         disk        Temporary file space 
public      disk        Public Stuff
root        disk        Home Directories

4 shares listed from 4 available 

2.2.2 Mounting When the user wants to mount a CIFS share, they will do it in one of two ways:


- Manual mount via mount_smbfs(1M):


# mount -F smbfs //[<workgroup>;][<user>[:<password>]@]<server>/<share> /<path>


For example, mounting the share 'public' as user 'foo', on server 'nano', would give:


# mount -F smbfs //nano/public /PUBLIC

Password:


- Via an automounter map entry:


# tail -1 /etc/auto_direct

/PUBLIC -fstype=smbfs //nano/public

% ls /PUBLIC

test1 test2 test3

% # grep public /etc/mnttab

//nano/public /mnt smbfs dev=4880000 1178054454


Notice that the manual mount prompted for a password, while (as expected) the automounter access cannot; authentication is possible without a user typing a password.


Once the CIFS share has been mounted, ordinary Solaris tools can be used to access the files. For the above scenario an example would be:


% soffice8 /PUBLIC/docs/somedoc.ods


CIFS does not support the same functionality as NFS on Solaris; a list of the expected behavioral differences can be found in section 2.2.4 Behavioural differences of filesystem commands


As usual in Solaris, you would use umount(1M) to unmount a share that had been manually mounted and you would see automounted shares automatically unmounted after a period of inactivity.


Mounts are not possible without authentication. If the server and client are part of an Active Directory domain, the user will have credentials acquired at login and they would be able to access a mounted CIFS share without a password. If Active Directory is not configured and the server requires a password, the user could use 'smbutil login' to enter their password or could place a hashed password in their $HOME/.nsmbrc file before they could successfully access the automounted share:


# smbutil login //[<workgroup>;][<user>[:<password>]@]<server>

For example:


% smbutil login //jones@nano
Password:


2.2.3 Nautilus 

Nautilus integration will not be present in the initial release. However, we intend to provide early access to our bits to the Nautilus team and work with them to ensure integration in their project. They will be able to use an ioctl() to determine if they need to prompt for a password as they attempt to browse into a share, and will be able to use mount_smbfs(1M).

2.2.4 Behavioural differences of system calls

There are some things that can't be done on an smbfs filesystem, either due to protocol or implementation limitations; this section describes them. Where possible, we model failures returned after the behaviour of other filesystems, e.g. link(2) and symlink(2) on pcfs return ENOSYS.

We will observe the behaviour of our client prototype to see if it presents any large surprises to user expectations.

2.3 High level Design diagram 



















3 Deliverables

The following deliverables will be putback into Solaris Nevada, and possibly into a Solaris 10 update.

3.1 User Space commands/libraries

3.1.1 smbutil

smbutil is a command-line utility that maps names, lists shares and performs other simple tasks as described in the man page. It links with libsmbfs.so. It will accept passwords and pass them to the kernel via a “login” subcommand and remove them with a “logout” subcommand. The man page is available here(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/smbutil.1.txt).

3.1.2 mount_smbfs

mount_smbfs is the smbfs-specific mount utility called by mount(1M). It links with libsmbfs.so. The man page is available here(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/mount_smbfs.1m.txt).

3.1.3 libsmbfs.so

libsmbfs.so knows how to map NetBIOS names to TCP addresses, and contains the RAP code to do some administration activities with the server (e.g. getting a list of shares). It calls into the netsmb module via ioctl(2). When the user uses either a mount or smbutil command, the ioctl() function is first called to resolve the machine/domain names, then to do protocol negotiation, and additionally for session setup and a tree connect.

3.1.4 Changes to sharectl(1M)

We will extend sharectl(1M) to display and change global settings for the CIFS client, such as timeouts and minumum authentication levels. These settings will be stored in SMF properties; the FMRI will be svc:/network/smb/client:default. An administrator will require the solaris.smf.manage authorization to change settings, as they do for other SMF changes.

3.2 Kernel modules

3.2.1 smbfs

smbfs is the Solaris virtual filesystem module with the vfsops and vnodeops. It will be patterned on the NFS Version 2 code in structure, and the CIFS-specific behavior will be ported in from Darwin. It calls into the netsmb module.

3.2.2 netsmb 

The netsmb module is somewhat similar to NFS's RPC layer. It forms packets, and sends and receives them according to the CIFS/SMB protocol.

3.3 Binary list

The following binaries will be delivered:

    SUNWsmbfskr       (MDB modules)
        kernel/kmdb/$ISA/nsmb
        kernel/kmdb/$ISA/smbfs

    SUNWsmbfsr          (SMF service)
        var/svc/manifest/network/smb/client.xml
        lib/svc/method/smb-client

    SUNWsmbfsu
        usr/kernel/drv/nsmb.conf
        usr/kernel/drv/$ISA/nsmb
        usr/kernel/drv/$ISA/smbfs
        usr/lib/fs/smbfs/mount
        usr/lib/fs/smbfs/umount
        usr/lib/fs/smbfs/smbutil
        usr/lib/fs/smbfs/$ISA/libshare_smbfs.so (sharctl plug-in)
        usr/lib/fs/smbfs/$ISA/libshare_smbfs.so.1
        usr/lib/$ISA/libsmbfs.so
        usr/lib/$ISA/libsmbfs.so.1
        usr/lib/llib-lsmbfs
        usr/lib/llib-lsmbfs.ln
        usr/lib/mdb/kvm/$ISA/nsmb.so
        usr/lib/mdb/kvm/$ISA/smbfs.so
        usr/bin/smbutil         (symlink to usr/lib/fs/smbfs/smbutil)



We also plan to update binaries these existing packages:

    SUNWcsr
        sbin/mount      (allow smbfs mount by non-root dir owner)
        sbin/umount     (allow smbfs umount by non-root dir owner)

    SUNWcsu
        usr/lib/autofs/automountd
        usr/lib/fs/nfs/libshare_nfs.so.1
        usr/lib/libshare.so.1
        usr/sbin/sharectl

    SUNWzoneu           (add zone config for /dev/nsmb)
        usr/lib/brand/native/platform.xml

3.4 Areas of Overlap

PSARC 2006/715 will introduce CIFS server functionality into Solaris. Both projects have their own NetBIOS implementation. The CIFS server project has a "redirector" (client) that implements only the minimum needed for MS-style RPC. We expect to replace the CIFS server redirector with an smbfs-based equivalent, but not until a follow-on project to integrate these two systems because the current functionality of the two clients is largely disjoint.

3.5 Other changes

We have not identified specific changes to 'snoop', but we plan to make any required changes as needed, to file bugs about the shortcomings, and to co-deliver the fixes with this project.



4 Interfaces

4.1 Exported interfaces

Interface

Classification

Comments

smbutil

Committed

See man page (http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/smbutil.1.txt)

mount_smbfs, umount_smbfs

Committed

See man page (http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/mount_smbfs.1m.txt)

nsmbrc(4)

Committed

See man page (http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/nsmbrc.4.txt)

libsmbfs.so

Project Private

Detailed design here

smbfs module

Consolidation Private

Detailed design here

nsmb module

Project Private

Detailed design here

SMF service

Committed

svc:/network/smbfs/client:default (enabled in generic_net_limited profile)

4.2 Imported interfaces 

Interface

Classification

Comments

libkrb5

Contract External

PSARC 2006/027, in Nevada

uconv routines

Consolidation Private

PSARC 2005/446, in Nevada

md4 routines

Consolidation Private

PSARC 2007/139, in Nevada

kTLI calls

Consolidation Private

See Section 8.5.2.3

PAM module

Consolidation Private

PSARC 2007/303, dependency



5 Design Considerations

5.1 Assumptions and Dependencies

5.2 Goals and Guidelines 

5.3 Development Methods

5.3.1 Description of methodology

In porting kernel module source from a BSD release, we have had to make choices about how to proceed. We wanted to create a code base that would be a maintainable part of Solaris, as we expect this code base to be extended to improve functionality in future, and we also want sustaining engineering to be as straightforward as possible. In that light, we rejected the option of using #define's to try to create a Darwin look-alike environment within Solaris, since that would not be familiar to future engineering staff. We instead want to write a top-level Solaris layer which replicates what other Solaris virtual filesystems do, and porting CIFS/SMB-specific logic and protocol code into that framework. This will constrain the ability to apply simple diffs from the Darwin code base to our Solaris code, but will make it easier to find the home-grown bugs that we will create during the port, and will make the code more approachable for people with Solaris expertise.

5.3.2 Comparison of Solaris and Darwin interfaces 

For sectionable areas of code such as vfsops and vnodes we have created interface tables for their functions in Solaris and functions in Darwin and analyzed how they compare to each other. Similarities and differences are noted and solutions devised which will allow code written for Darwin to interface with Solaris.

5.3.3 Re-use and adaptation of existing Solaris code 

The nfsv2 code will be used as a basis for the filesystem operations portion of smbfs. The nfsv2 code will be pared down, and will have the appropriate data structures and functions put into it.

5.3.4 Porting existing Darwin smbfs code 

Darwin is a Unix type OS forked from 4.4 BSD. Darwin's kernel is based on a combination of Mach 3.0, BSD and some proprietary functionality. SMBFS is taken from the NetBSD code and ported over to Darwin. Extra functionality such as KeyChains, active directory support and support for the GUI is added to SMBFS code.

We started with Darwin's SMBFS code(smb217-2 version), and in the process of porting it to Solaris, changed the code related to mbuf's/memory allocations, sleep/wakeup mechanisms, network operations and the general driver interface for handling the minor nodes and related device operations.

In the user context code, we are not going to port the IDL compiler code for compiling DCE/RPC stubs, nor the pre-generated DCE/RPC stubs or runtime. We will revisit this when this project and the CIFS server project are both delivered.

By choosing Darwin's existing functional code base for smb-217.2, we will avoid much development and debugging time as the code has had a lot of soak time in active usage.

5.3.5 Debugging via Tracing input and output on the wire 

All the packets which are sent over the wire can be traced using Ethereal (aka Wireshark) or “snoop”, both of which understand the SMB protocol. Ethereal shows the packet trace, each parameter, and the values which are sent over the wire. So, a packet captured from a Windows/CIFS client to a CIFS Server(Windows/Samba) can be compared with the packet generated by our CIFS client sent to a CIFS server to find out if we differ in any parameters and some comparable values. The team will also insert some static dtrace probes to aid debugging.



6 Security Considerations

6.1 Authentication

CIFS/SMB has had several different authentication models over time and many are still supported. Simple password schemes were used in the early life of the protocol, and as security awareness has grown, the quality and quantity of authentication methods have improved, culminating with the use of Kerberos authentication in Active Directory environments.

During connection setup, a CIFS client negotiates with the server to select an authentication level acceptable to both. Either side can decline the connection if the outcome of the negotiation results in an unacceptable (weak) method. Our implementation will, by default, not offer to use the "weak" authentication methods. Those methods are only used on very old servers, so no compatibility problems are expected from this choice. (This is the same policy default that's set on modern Windows clients.)

A mount of an smbfs filesystem will not be possible without valid authentication information present; authentication without a password prompt can be done with a Kerberos ticket for Active Directory sites or via 'smbutil login' or a hashed password in $HOME/.nsmbrc for non-AD sites.

If a user already has a Kerberos TGT from a Kerberos or Active Directory server, the CIFS client will be able to access and use that credential as a basis of connection authentication.

'smbutil login' can be used to store a password in the kernel via an ioctl(). Passwords will be stored separately for each UID/server and will be accessed when needed for authentication. This prevents Joe from using Fred's previously stored password. To better deal with sites where user accounts have synchronized passwords, we will co-deliver a PAM module to use the ioctl() mechanism to save the user's password for future use, but this is not committed in the first release. 'smbutil login' will not interact with Kerberos; AD users must use kinit(1) or PAM to make use of Kerberos credentials.

In CIFS usage, the UNC name can include a password, and mount_smbfs(1M) accepts this. We will warn users about the risks involved with this and recommend use of 'smbutil login' instead. It will be possible to generate a hashed password with 'smbutil crypt' and to then put that hashed password into the user's' $HOME/.nsmbrc file, such that mount_smbfs can use it later. Unattended mounts from /etc/vfstab will be possible with a UNC name with a password, but we will warn against this in our documentation.

The security model used to access a given CIFS share depends on both the "dialect" negotiated in the "Session Setup" exchange and the administrative choices made for the share by the admin. The dialect factor is generally no longer an issue for the default case; the dialect “NT LM 0.12” is offered as a default choice for the following servers: Win9X, WinNT, Win2K, WinXP, Win2003 and Samba. It is also available on Vista if clients select it. But server administrators can change authentication defaults for certain situations, so the client will sometimes encounter different situations. If a negotiated security model is too weak per the preferences files on the client, the client will close the connection with the server.

Client configuration settings for minimum permissible security model can be set for either the whole system via SMF, or for an individual user via $HOME/.nsmbrc. Policy is applied in such a way that the highest applicable level of authentication listed in either source is used. The setting, “minauth”, is similar to LmCompatibilityLevel, which is how Microsoft operating systems control authentication preferences.

The following is a listing of the authentication models; all will supported in the CIFS client except as noted.

6.1.1 Anonymous login

Old servers prior to Windows NT SP 4 accept a "Session Setup" packet with a null username and password. Modern Windows servers do not accept this authentication for file access by default, so we do not see the need to support it.

6.1.2 Plaintext passwords 

Modern CIFS servers can be set to permit plaintext passwords with simple ASCII encoding, though this is never the default because the password can be revealed so easily. If a server is set up this way, we would need to supply the plaintext password or decline to work with that CIFS server. By default, the administrator would have to lower the system-wide “minauth” setting to permit interoperability in this case.

6.1.3 LM Challenge / Response 

To get away from passwords sent over the wire, a password-based scheme was invented and remains supported. First, the server stores the user's password encrypted via DES with a well-known key; this stored info is called the "LM Hash". At Session Setup time, the server generates a random string of bytes and sends them to the client as a "challenge". Both the client and server encrypt the challenge bytes via DES, using the LM Hash as the key. The client sends the encrypted result to the server, which accepts the result if it matches its computations. This is not considered robust, because both the usual method for generating the challenge can permit replay attacks, and because the specific conversion algorithm for the LM Hash makes dictionary attacks simpler. We will disable this mode by default via an SMF property, which will result in the client declining to set up a connection with such a server; it will be possible for the sysadmin to permit LM usage if necessary.

6.1.4 NTLM Challenge / Response 

This upgraded password-based scheme improves the above scheme by using Unicode UCS-2LE-encoded mixed-case passwords and RFC-1320 MD4 processing instead of DES with a well-known key. The result is better; some clients compromise this by sending both an LM Response and an NTLM response in the same Session Setup packet. This will by default be the lowest level of authentication we will permit, and is by default the weakest form of authentication supported by most CIFS servers.

6.1.5 NTLMv2 

NTLMv2 (apart from the Extended Security below) does not appear to be used by default on existing CIFS servers, but modern ones can be configured to use it instead of NTLM. This is not negotiated in any way, so if the server uses this, the client must be configured to use it or must try it in addition to other schemes it tries. It adds some random data and a time stamp to prevent replay attacks and replaces MD4 with HMAC-MD5 (RFC 2104) to make dictionary attacks more expensive, but it still has the same guessability weaknesses as NTLM.

6.1.6 Extended Security and Kerberos 

If the CIFS client uses the NTLM 0.12 protocol dialect and specifies the CAP_EXTENDED_SECURITY capability in the Negotiate exchange, modern CIFS servers agree to use Extended Security, which was introduced as a very different basis for authentication. The server response to the Negotiate includes a security blob with an "SPNEGO initiate" packet, which the client returns with a credential in the Session Setup request. The Session Setup will complete with the server picking a security flavor, which is usually Kerberos but could also be another challenge/response method. Once the Session Setup is complete, the client and the server are authenticated; the integrity of the TCP connection is assumed to be sufficient to secure CIFS/SMB traffic.

When used with Active Directory, Kerberos authentication permits true single-sign-on, where the login password permits you to access CIFS shares without typing further passwords. Solaris has the infrastructure to work with AD's Kerberos and LDAP implementations, so we are optimistic that this will be supportable. The proposed approach for this is to uncomment the code and see what undefined symbols we need, and then to see if we can resolve them readily from either Solaris or Darwin sources. This will not be particularly easy work to estimate correctly.

Modern Windows servers are capable of packet signing, a.k.a. integrity, based on Kerberos. We will try to support this in our first release if we can, but it is not committed.

Microsoft's Active Directory adds so-called “secret sauce” to the TGT it returns, which contains authorization information. CIFS servers need this, but clients do not, so we can ignore this information.

6.2 Multi-user mounts 
6.2.1 Challenges of Multi-user mounts

In Darwin, the smbfs module assumes that a mount will only be used by one user. This looks odd from a Solaris perspective. However, single-user mounts are a more natural fit onto the CIFS protocol for the following reasons:

The implications of (a) above lead to some of the larger challenges of this project. Ideally, every local open in a CIFS mount would result in a CIFS open ("over the wire") so that access control and sharing semantics are handled correctly on the CIFS server. The Darwin code (on which our implementation is based) currently shares the CIFS file handles, with just one per file or directory. Sharing CIFS handles works only with single-user mounts.

For our first putback, we will keep single-user mounts. All operations done on a mounted CIFS filesystem will be done on behalf of the username specified on the mount command because of the ownership of the authenticated connection. The permissions for the mount point will determine which users will be able to use the filesystem; mount_smbfs(1M) supports uid/gid/fileperms/dirperms options to support this. Users will be able to do smbfs mounts and unmounts on directories they own.

Unlike NFS, the root user has no special treatment by CIFS servers; proper credentials in the form of a typed password, a previously stored password, or a personal Kerberos ticket must be available to mount. Since UIDs are not used, no special handling for the root user is configurable. Root can mount a client filesystem in more places, and root can also bypass permissions on mount points.

6.2.2 Roadmap to Multi-user mounts

In the longer term, single-user mounts are not acceptable for Solaris. For true multi-user mounts, we need to take these steps:

6.3 RBAC and privileges 

The CIFS client should follow the example of NFS here, as all that should be necessary is to make sure we have secpolicy* checks at appropriate places. The NFSv2 client calls secpolicy_fs_mount(), secpolicy_fs_unmount(), secpolicy_vnode_setattr(), secpolicy_vnode_access() and secpolicy_fs_linkdir(); we likely want all of these in smbfs, though an over-the-wire access check would replace the secpolicy_vnode_access() call.

We plan to permit regular users to mount on directories they own (not just those they can write to as provided for in Enabling user mounts in Solaris PSARC/2004/047). This grants users better usability with single-user mounts while limiting their ability to affect others. The mounts are still done nosuid,nodevices unless all privileges are asserted. We will do this by adding a new rights profile which will run mount_smbfs with SYS_MOUNT, and to add this rights profile to the “Basic Solaris User” rights profile. For “smbfs” filesystems, /sbin/mount will use pfexec(1) to run mount_smbfs with our new rights profile.

Following along with permitting regular users to mount on directories they own, they will also be permitted to umount shares they've mounted. A separate umount_smbfs will be delivered which will be granted the sys_mount privilege in the "Basic Solaris User" Rights Profile." The smbfs version of VFS_UNMOUNT() will confirm the ownership of the covered vnode before permitting the unmount.

6.4 Name Resolution

The CIFS client always tries to use gethostbyname() to resolve hostnames, and by default falls back to use NetBIOS name resolution (NBNS) if the name was not resolved. The use of NBNS can be risky due to past known exploits, so we will add an SMF property to disable the fallback to NBNS; the default setting of the property will permit the fallback so that Solaris clients in Microsoft environments will work out of the box.

6.5 Unattended Access

All access to CIFS shares will require either an interactive invocation of smbfs_mount (to establish CIFS credentials) or an invocation of "smbutil login", to establish a default Windows account name and password to be used for CIFS mounts, or the presence of a matching hashed password in $HOME/.nsmbrc. Unattended access to filesystems mounted in /etc/vfstab could be achieved by placing a hashed password in root's $HOME/.nsmbrc; the weakness of the hash will be documented and world-readable .nsmbrc files will be ignored.

7 Architectural Strategies

7.1 Use of smb-217.2 from Darwin

We chose to use code from a BSD variant because of licensing which was compatible with the Solaris kernel and the CDDL, and we chose to use Darwin since it seemed like the most relevant and recent of the BSDs. The smbfs version at the time was smb-217.2. We have been tracking changes made since we took our copy of the code.

7.2 Use of PSARC/2005/446 interfaces (uconv functions) which implement codeset conversion 

Although the code base of smb217-2 did come with codeset conversion capabilities which we could have ported, we have decided to standardize on the Solaris interfaces providing this capability, minimizing code duplication within the Solaris kernel environment.

7.3 Use of nfsv2 vfsops and vnops code as a re-engineering base 

The choice of using nfsv2 as a base as opposed to nfsv4 is due to it being simpler, and so it is easier to pare it down to use as a base for the smbfs code.

7.4 Error detection and recovery 

The netsmb module does the majority of it's error detection and recovery itself. Typical errors are with the I/O between the CIFS server and CIFS client or related to memory. For all the error conditions, the information is logged via syslog, allocated memory is cleaned up, and the program exits gracefully.

All the buffers allocated in the netsmb module when sending the request/response for each of the calls at the time of setup are cleared once the information is copied out to the user space before the ioctl() returns. So in the user level if libsmbfs.so fails for any reason, the program just exits printing the error to stdout.

The smbutil command does not have much potential for error. It simply requests an operation and receives the data back from libsmbfs.so and prints to stdout.

7.5 Memory management policies

7.5.1 Memory allocation

The standard kernel memory allocator calls (kmem_alloc() and friends) will be used; the conversion from Darwin's malloc() family of calls is mostly obvious.

7.5.2 Mbufs vs. mblks 

All the packets for negotiation, session setup, write and read are built in Darwin using mbufs. For Solaris, we will have a conversion layer called MBCHAIN which maps the mbuf operations to operations on data blocks associated with mblks instead. mblk_t's are similar to mbufs on BSD with equivalent pointers for traversing and accessing the data. MBCHAIN and MDCHAIN are kept intact from the Darwin code and used along with mblk_t's so that no major code changes are required.

7.6 Concurrency and synchronization

7.6.1 Threading

Darwin uses current_thread()/current_proc() interfaces to check something in the current thread or process; these will be replaced with references to curthread and curproc in Solaris.

7.6.2 Thread synchronization primitives 

BSD

msleep() and wakeup() are used to handle event based process blocking. If a process has to wait for an external event, it is put on sleep by msleep(). It is later woken up by wakeup() call to indicate the resource the process was blocking on is available now.

Solaris

Condition variables are the standard form of thread synchronization on Solaris when a signaling algorithm is being used. They are designed to be used with mutex locks which allow an atomic check of the condition. cv_wait() and cv_timedwait() are called to put the thread to sleep waiting on a change of condition variable or a signal. cv_signal() is used to signal the completion of the usage of the resource to a process that is waiting on it.

Darwin Function

Solaris Function

msleep()

cv_wait()/cv_timedwait()/cv_wait_sig()

wakeup()

cv_signal()

7.6.3 Timers 

Darwin uses the nanotime() call to get a high-resolution version of the current time. This will be replaced on Solaris by gethrestime().

Darwin uses timespeccmp()/timespecadd()/timespecsub() to deal with time intervals, which are supported in Solaris.

7.6.4 Concurrent access issues 

In Windows environments, a file create or open can specify the "share access" to be granted to another process trying to open the file. A Windows app will often use the FILE_NO_SHARE OR FILE_SHARE_READ to prohibit all competing access or to deny write access to other openers. This is extended to the over-the-wire case by support in the CIFS protocol. This means that two processes doing this cannot accidentally clobber a file's contents with competing writes. The only other protection from this would be byte-range locking, which is not in scope.

In Unix/Linux environments, the open(2) API has not accepted an argument to specify this; matching this, our client's opens will not impose restrictions to other processes (i.e. NT_CREATE_ANDX's ShareAccess is always set to NTCREATEX_SHARE_ACCESS_ALL) or to reopen files to support fcntl()'s F_SHARE semantics. Future work could add support for fcntl()'s F_SHARE interface on files which are already open. The CIFS server project has plans to add a new open(2) variant which accepts a share mode argument to be applied at open time, and we would like to support it when it is available.

7.6.5 TIMEOUT and “up-call” support in the network layer

In the smb_iod_recvall() function, the BSD code sleeps at the top of a service loop until either: (a) network data arrives, or (b) some local request is enqueued. The wakeup for network input uses an “up-call” from the network stack. Also, reads of network data on BSD can be configured to wait no longer than some timeout, preventing this service loop from getting stuck waiting for incoming network data.

Solaris doesn't have support for the “up-call” from the network stack, so we redesigned the service loop to be simply a “reader thread” (all it does is recv on the network endpoint) and arranged for callers to perform their own network sends (after taking appropriate serialization locks) .

7.7 Communication mechanisms

7.7.1 Kernel authorization

Darwin uses the routines suser()/kauth_cred_getuid()/kauth_cred_getgid() to identify a proper user. We will replace these with calls to crgetuid() and crgetgid() on Solaris. These calls are used by the NetSMB code while setting up the connection for that particular user and used for authorizing a user. There is no authentication involved in the local machine while doing CIFS authentication.

7.7.2 Byte ordering 

For the code to be portable, we need to ensure that the integers are properly converted to and from the network byte order. As the CIFS protocol defines network byte order as little-endian we must select functions supporting that conversion. The functions we use are:

Function

Usage

htoles(x)

host to little endian short

letohs(x)

little endian to host short

htobes(x)

host to big endian short

betohs(x)

big endian to host short

Currently, we are using the Darwin's implementation of the Byteorder routines for Solaris. As this code is also present in Solaris, we should eventually make use of the Solaris code.

7.8 Other topics

7.8.1 UIO routines

Darwin uses these routines to access fields in the uio(9s) structure; we will use direct field access in Solaris.

Function

Usage

uio_isuserspace()

Check the uio_segflag and return if its user space.

uio_iovcnt()

Return the active iovecs for the given uio_t.

uio_resid()

Return the residual IO value for the given uio_t.

uio_curriovbase()

Return base address of current iovec associated with the given uio_t.

uio_curriovlen()

Return the length of the current iovec associated with the give uio_t.

uio_update()

Update the given uio_t with the a_count of completed IO.

7.8.2 smb_cred_t

smb_cred_t encapsulates the context in which the VFS operation is being performed, which holds the process ID and a pointer to a cred structure.

The use of this structure to pass the context pervades the code; here is where it can be found:

Basic creation and initialization functions:

Function

Comments

smb_scred_init()

Initialize the context.

smb_sigintr()

Calls vfs_context_issignal with SMB_SIGMASK

vfs_context_ucred()

Return the credential structure.

vfs_context_is64bit()

Returns true if the proc is 64-bit.

vfs_context_rele()

Release the context.

vfs_context_issignal()

Return the pending signals if any for that particular process. (ISSIG() may be used.)

vfs_context_create()

Create a new context. If not initialize.

Other functions:

       smbfs_vinvalbuf()
       smbi_getattr()
       smbi_setattr()
       smbi_open()
       smbi_close()
       smbi_fsync()
       smbfs_readvdir()
       smbfs_readvnode()
       smbfs_vinvalbuf_internal()
       smbfs_vinvalbuf()
       smbfs_writevnode()
       smbfs_mount()
       smbfs_root()
       smbfs_start()
       smbfs_vfs_getattr()
       smbfs_sync()
       smbfs_unmount()
       smbfs_sysctl()
       smbfs_vget()
       smbfs_fhtovp()
       smbfs_vptofh()
       smb_flushvp()
       smbfs_composeacl()
       smbfs_close()
       smbfs_getattr()
       smbfs_setattr()
       smbfs_read()
       smbfs_write()
       smbfs_fixinheritance()
       smbfs_composeacl()
       smbfs_create()
       smbfs_create0()
       smbfs_remove()
       smbfs_rename()
       smbfs_link()
       smbfs_symlink()
       smbfs_readlink()
       smbfs_mknod()
       smbfs_mkdir()
       smbfs_rmdir()
       smbfs_readdir()
       smbfs_fsync()
       smbfs_pathconf()
       smbfs_ioctl()
       smbfs_advlock()
       smbfs_lookup()
       smbfs_offtoblk()
       smbfs_blktooff()
       smbfs_pagein()
       smbfs_pageout()
       smbfs_setxattr()
       smbfs_listxattr()
       smbfs_removexattr()
       smbfs_getxattr()
       smbfs_open()
       smbfs_vinvalbuf()
       smbfs_reclaim()
       smbfs_inactive()
       smbfs_mmap()
       smbfs_mnomap()

7.8.3 Codeset conversions

In Darwin, the ICONV module inside the kernel does the translation of UCS-2 to cp437 conversions because the path name and file names sent by the SMB servers are always in the Unicode format. The Solaris kernel, in order to understand them, has to translate to the native codeset and when it has to send something to the server, it has to send it in Unicode format.

The darwin smbfs uses UTF-8 <-> UCS-2 iconv if CAP_UNICODE capability is returned from server and otherwise, it uses UTF-8 <-> UCS-2 <-> CP437 code conversion.

In Solaris, the PSARC/2005/446 interfaces (uconv functions) implement codeset conversion. However, currently UCS-2 and pc437 are not supported; UCS-2 is no longer in common usage, and pc437 is the original character set of the IBM PC which is a subset of Unicode, and is only used as a fallback position if Unicode failed.

The uconv functions support the necessary Unicode conversions (but with a different name). UCS-2 is no longer recommended even from Microsoft and should be instead replaced with UTF-16. They are the same except that the UTF-16 (which Microsoft Windows supports these days) can support entire Unicode coding space of U+0000 to U+10FFFF. UCS-2 only supports so-called Basic Multilingual Plane (BMP) which is U+0000 to U+FFFF, i.e., just 16-bit range of Unicode not the current 21-bit range.

UTF-16 also differs in a sense that even though the scalar data type size is of uint_16, when it has to represent Unicode characters between U+10000 to U+10FFFF, it will use two 16-bit units.

So in summary, for UTF-8 <-> UCS-2 conversions we can replace them with UTF-8 <-> UTF-16 code conversions. For pc437, we will expect that any CIFS server we are interacting with supports Unicode, and not support this codeset either.

More information on the uconv functions can be found here: http://sac.sfbay.sun.com/Archives/CaseLog/arc/PSARC/2005/446/materials/uconv_functions.9f

We also use the “u8_textprep” function in the “uconv” k-mod, for case conversion.

7.8.4 Zones 

Zones is a virtualization solution for Solaris which supports multiple virtual hosts on a single Solaris kernel instance. Kernel modules must be modified to use allocated memory and to ensure that threads are not able to access resources they should not or escalate privileges.

The expectation for the CIFS client is that it will work the same way in all zones without behavioural differences.

7.8.4.1 Conversion checklist 

Almost all global variables (excluding stuff like tunables) must now be elements in a per-zone globals structure; the test for this is to compile your code and run 'nm' on the object files, and see what shows up as type OBJT.

Module startup functions must call zone_key_create() with a key and callbacks to an init routine, a shutdown routine and a fini routine; init/fini alloc/free the per-zone global struct, and the shutdown thread should message all threads in the zone to stop (which means all threads need to poll on something so they can be told to stop).

References to former globals must use zone_getspecific() with the key to get a pointer to the per-zone globals, and then dereference the item needed.

Creds, networking setup, file namespace are all per-zone, and threads must not operate on data structures from other zones; most routines can have ASSERTs, but VOP_INACTIVE() can be called on vnode recycling, so it should have an async handoff to the correct zone like NFS does. This is important because zones are used to implement compartmentalized security in the Solaris Trusted Extensions (aka Rampart).

7.8.4.2 Notes on the netsmb module 

The netsmb module exports a device node which can be opened and ioctl()'ed to set up connections. In Darwin, it sets up 1024 device nodes to service connections. For Solaris, we will implement a clonable device driver which allocates a smb_dev_state_t structure as needed each time /dev/nsmb is opened, with no small arbitrary limit per-zone or per-system.

The zone "init" routine will set up the per-zone state corresponding to globals used in Darwin, with the fixed-size smb_dev_state_t table dropped. Simple lookup tables and device linkage tables (e.g. nsmb_ops) can be left as globals. From analysis, the variables in netsmb that must be per-zone is small: dev_lck, smb_iod_next, smb_major, smb_minor, smb_vclist, smb_vcnext and smbechoes. The only threads created, for the smb_iod's, have a well-defined termination method, so iterating over the current iod's and setting that bit will work.

The nsmb_ioctl() will also have to fail if called somehow from a thread belonging to another zone.

7.8.4.3 Notes on the smbfs module 

Largely, smbfs can mimic what NFSv2 uses for Zones. Particular attention must be paid to thread creation and termination, as locking and concurrency issues there will be the thorniest problems. When looking for Zones calls, the interesting routines to look for are:

An important thing NOT to copy is nfs_zone(), which permits cross-zone filesystem access for network installs; this is not appropriate for CIFS/SMB.

8 Detailed System Design

8.1 smbutil

8.1.1 Purpose

smbutil is a user-visible command to map names, list shares and other simple things. This command makes use of the interface provided by libsmbfs.so library. This processes the output given by libsmbfs.so library and displays it to the user. There is not much occurring in this code other than issuing calls to the library and displaying the results.

We will extend it to accept passwords and pass them to the kernel to be stored for later use. The expected normal mode of operation is for smbutil to prompt the user for a password, but it will accept a password in a UNC name on the command line if given. The reasons for this are to permit access from command scripts and to maintain compatability with the behaviour of the Darwin code and the behaviour of Microsoft's "net use" command.

smbutil's "view" subcommand is analogous to "showmount -e <host>" usage for NFS and to the "smbclient -L <host>" usage for the Samba ftp-like client. We do not believe it is appropriate to try to unify these commands because of the NFS-centric nature of the showmount command and because of licensing challenges in mixing smbutil and smbclient sources. We will consider whether there is value in integrating with the dfshares and dfmounts commands, which may not be widely used.

smbutil's “crypt” subcommand will prompt for a password and emit a hashed version to standard output, suitable for cutting and pasting into $HOME/.nsmbrc.

8.1.2 Interfaces

See man page(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/smbutil.1.txt)

8.2 mount_smbfs

8.2.1 Purpose

mount_smbfs is the smbfs-specific mount utility called by mount(1M). It links with libsmbfs.so.

8.2.2 Interfaces

See man page(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/mount_smbfs.1m.txt)

8.3 libsmbfs.so

8.3.1 Purpose

This library provides the interface to the Kernel NSMB driver through ioctl() calls. It has the code to call ioctl() to set up authenticated connections. Above that, libsmbfs implements the RAP functionality to do some administrative activities with the CIFS server. All this is done over the transaction SMB to search for a machine on the network, to get the share list, and to login at the user level for the commands 'smbutil' and 'mount_smbfs'.

8.3.2 Interfaces

libsmbfs.so exports the following interfaces, stability level 'Project Private':

Function

Usage

nb_ctx_create()

Create a NetBIOS context

nb_ctx_readrcsection()

Read the user's rc file

nb_ctx_resolve()

Resolve the name

nbns_resolvename()

Resolve name

nbns_getnodestatus()

Ping the machine on port 137

smb_ctx_setshare()

Set the share which we want to examine

smb_netshareenum()

RPC to call after the session is setup to get the list of shares

smb_ctx_lookup()

Setup the session by calling the appropriate ioctls

8.3.3 RAP

RAP (Remote Administration Protocol) 

This is used to submit status requests to a CIFS server and obtain the results from the server and is based on the transaction SMB in the CIFS protocol. The transaction protocol is used when there is lots of data which needs to be exchanged, and is layered above the SMB header. More information about how to use the RAP commands and the parameters to be sent to the CIFS server can be obtained from the link below.

Note: we currently use and implement only NETSHAREENUM in the table below (for “smbutil view”).

CIFS RAP Specification(http://jurassic.eng/home/pk162140/proj_docs/draft-leach-cifs-rap-spec-00.txt)

RAP commands:

Command

Result

NETSHAREENUM

List shares on a server.

NETSERVERENUM2

Enumerate the computers on a particular domain.

NETSERVERGETINFO

Get info about a server.

NETSHAREGETINFO

Get info about a particular share.

NETWKSTAUSERLOGON

Log a user on a remote CIFS server.

NETWKSTAUSERLOGOFF

Log off a user from a remote CIFS server.

NETUSERGETINFO

Get detailed information about a particular user.

NETWKSTAGETINFO

Get detailed information about a workstation.

SAMOEMCHANGEPASSWORD

Change user's password on a CIFS server.



8.4 smbfs

8.4.1 Purpose

The smbfs module provides a VFS plugin to satisfy all filesystem operations on CIFS/SMB filesystems.

8.4.2 Interfaces

Code will be based off of nfsv2 codebase, stripped of non applicable code and repopulated with Darwin smbfs code where appropriate as listed below. The stability level of all vfsops and vnodeops interfaces is 'Consolidation Private'.

8.4.2.1 vfsops

Most of the vfsops are derived from the Solaris NFS code, with excerpts taken from the Darwin code.

Solaris VFS

smbfs function

Comments

vfs_mount

smbfs_mount

Solaris NFS, Darwin

vfs_unmount

smbfs_unmount

Solaris NFS, Darwin

vfs_root

smbfs_root

Solaris NFS, Darwin

vfs_statvfs

smbfs_statvfs

Solaris NFS, Darwin

vfs_sync

smbfs_sync

Solaris NFS, Darwin

vfs_vget

fs_nosys

This operation is only needed in file systems that suport export via NFS or CIFS, which smbfs does not support.

vfs_mountroot

fs_nosys

Root on smbfs is not supported.

vfs_freevfs

smbfs_freevfs

Solaris NFS

vfs_vnstate

N/A

Solaris nfsv2 nulls this. We will NULL as well.

8.4.2.2 vnodeops

Derived from the Solaris NFSv2 code, stripped of non applicable code and repopulated with Darwin smbfs code where appropriate.

Solaris VFS

smbfs function

Comments

vop_open

smbfs_open

Gets the attributes, checks for permissions and then calls smbfs_smb_open()

vop_close

smbfs_close

Flushes and invalidates all dirty pages and calls smbfs_smb_close(). Removes entries from attribute cache.

vop_read

smbfs_read

Breaks into chunks and calls smbfs_readvnode(). This calls smb_read(), which calls smb_smb_read().

vop_write

smbfs_write

Breaks into chunks, calls smbfs_writevnode() -> smb_write(). Finally smb_smb_write() is called.

vop_ioctl

fs_nosys

the Darwin version returns EINVAL, we will return ENOTTY per Solaris convention

vop_getattr

smbfs_getattr

Does an attribute cache lookup, calls smbfs_smb_lookup() and then updates the attribute cache.

vop_setattr

smbfs_setattr

If file size needs to be set, call smbfs_smb_setfsize() If atime or mtime needs to be set, based on whether it is NT4 or DOS, call smbfs_smb_setpattr() or other functions. Then invalidate the attr cache and update the attr cache with the modified values.

vop_access

smbfs_access


vop_lookup

smbfs_lookup

also used for named streams, so extended attribute code in Darwin will convert to calling this with a LOOKUP_XATTR flag

 

smbfs_setxattr

Darwin code (not used)

 

smbfs_removexattr

Darwin code (not used)

 

smbfs_listxattr

Darwin code (not used)

vop_create

smbfs_create0

calls smbfs_create with vnop_create_args, nulls second & third args

vop_remove

smbfs_remove

Does a directory name purge and then smbfs_smb_delete().

vop_link

fs_nosys

Darwin code not be used for phase 1.

vop_rename

smbfs_rename

Calls smbfs_smb_delete() to delete the target smbnode and then calls smbfs_smb_rename().

vop_mkdir

smbfs_mkdir

Calls smbfs_smb_mkdir(). Then updates cached copy of mtime and marks attr cache invalid.

vop_rmdir

smbfs_rmdir

Calls smbfs_smb_rmdir(), updates cached copy of mtime and marks attr cache invalid, purges the directory cache.

vop_readdir

smbfs_readdir

Calls smbfs_readvnode()

vop_symlink

fs_nosys

Darwin code not be used for phase 1.

vop_readlink

fs_nosys

Darwin code not be used for phase 1.

vop_fsync

smbfs_fsync

Calls smb_flushvp()

vop_inactive

smbfs_inactive

Drops reference on smbnode.

vop_fid

fs_nosys

This operation is only needed in file systems that suport export via NFS or CIFS, which smbfs does not support.

vop_rwlock

smbfs_rwlock


vop_rwunlock

smbfs_rwunlock


vop_seek

smbfs_seek

validate file offset

vop_cmp

N/A

Darwin code, N/A to Solaris.

vop_frlock

smbfs_frlock

Just calls fs_frlock() in phase 1 (local locking only).
Later will do over-the-wire locking.

vop_space

smbfs_space

 

vop_realvp

fs_nosys

Will not be used for SMBFS

vop_getpage

fs_nosys

No mmap support in phase 1.

vop_putpage

fs_nosys

No mmap support in phase 1.

vop_map

fs_nosys

No mmap support in phase 1.

vop_addmap

fs_nosys

No mmap support in phase 1.

vop_delmap

fs_nosys

No mmap support in phase 1.

vop_poll

N/A

Darwin code, N/A to Solaris.

vop_dump

fs_nosys

Dump on smbfs not supported.

vop_pathconf

smbfs_pathconf


vop_pageio

fs_nosys

No mmap support in phase 1.

vop_dumpctl

N/A

Darwin code, N/A to Solaris.

vop_dispose

N/A

Darwin code, N/A to Solaris.

vop_setsecattr

fs_nosys

No ACL support in phase 1.

vop_getsecattr

noop_vnodeop

No ACL support in phase 1.
Common code “fakes up” an ACL for us.

vop_shrlock

smbfs_shrlock

DOS-style share reservations, not supported in phase 1.
Common code handles this for now.

vop_vnevent

NULL

Not in our vnops table. (not supported)

N/A

smbfs_blktooff

not necessary in Solaris

N/A

smbfs_offtoblk

not necessary in Solaris

8.5 netsmb

8.5.1 Purpose

The netsmb module is the device driver module which deals with the implementation of the network connections to the CIFS server. It appears in the device namespace as /dev/nsmb. It uses the MBLK interfaces for storing/retrieving the packet information, and the kTLI interface for network interaction, CRYPTO module for the encryption of passwords, path and file names, and UCONV module for the Unicode conversions. The user level library libsmbfs.so makes ioctl() calls which are translated to the ioctl()'s in this module.

The stability level of these ioctl()'s is 'Project Private'. The stability level of the device name is 'Consolidation Private'.

8.5.2 Interfaces

8.5.2.1 ioctl()'s available from device driver

ioctl

Usage

SMBIOC_GETVERS

verify interface version

SMBIOC_NEGOTIATE

negotiate a dialect and ground rules

SMBIOC_SSNSETUP

set up a session for the current user

SMBIOC_TCON

issue a tree connect to a particular share

SMBIOC_REQUEST

send an SMB protocol request

SMBIOC_T2RQ

issue a TRANS2 call

SMBIOC_LOOKUP

lookup a machine or domain name

SMBIOC_READ

alternate file read interface

SMBIOC_WRITE

alternate file write interface

SMBIOC_TDIS

disconnect from a file tree

SMBIOC_FLAGS2

get flags values

SMBIOC_PK_ADD

add a stored password for this UID/username/server combo

SMBIOC_PK_CHK

return true if a password is stored for this UID/username/server combo

SMBIOC_PK_DEL

delete stored password for this UID/username/server combo

SMBIOC_PK_DEL_OWNER

delete all stored passwords owned by the caller

SMBIOC_PK_DEL_EVERYONE

delete all stored passwords owned (all users)
Privileged operation.

8.5.2.2 Interfaces exported to smbfs module

The following interfaces are exported for use by the smbfs module, at stability level 'Project Private'.

void smb_scred_init(struct smb_cred *scred, vfs_context_t vfsctx);
int  smb_read(struct smb_share *ssp, u_int16_t fid, uio_t uio, struct smb_cred *scred);
int  smb_write(struct smb_share *ssp, u_int16_t fid, uio_t uio, struct smb_cred *scred, int timo);
int  smb_sigintr(vfs_context_t);
int  smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, int len, int caseopt, int *lenp);
int  smb_dev2share(int fd, struct smb_share **sspp);
void smb_share_unlock(struct smb_share *ssp, struct proc *p);
void smb_share_put(struct smb_share *ssp, struct smb_cred *scred);
void smb_iod_shutdown_share(struct smb_share *ssp);

8.5.2.3 Interface to networking code

During our porting efforts, we learned that the Darwin code depends on the ability to build separate message chains and concatenate them later. This is used for things like building the "parameters" and "data" sections of an RAP request. Similarly, the Darwin code parses some messages by making (reference) duplicates (dupmsg) and trimming to the sections desired (parameters, data).

We changed to (k)TLI because that interface supports sending and receiving mblk chains. We use mblk chains to support dissection and reassembly of messages.

Port 137 is used in sending and receiving the data to SMB servers and port 139 is used by the user level code in resolving the NetBIOS name. Packets are built into the MBLK data block using the MBCHAIN routines in a manner acceptable to the SMB protocol and tli_send() is used to send it out onto the network. Data is received in the same manner in the form of message block using til_recv().

TCP connections are made when upper levels request traffic, and are closed after use by smbutil and left open by smbfs. The smbfs code may have some ability to multiplex CIFS traffic to the same server over virtual circuits; we will examine this code with an eye to behaviour on busy multiuser clients. We will also examine the value of an inactivity timeout. We will also study the use of port 445 (Raw TCP) for sending and receiving packets.

8.5.3 Consumers of the NetSMB module

The consumers of netsmb module includes the smbfs module, and the libsmbfs.so library in the context of the CIFS client. Although any application which wants to setup a connection to a SMB server could use this module, currently we want to restrict it's use by other modules.



9 Acknowledgements 

The format of this document is adapted from: http://www.construx.com/survivalguide/desspec.htm Web page copyright © 1993-2002 Steven C. McConnell. Permission is hereby given to copy, adapt, and distribute this material as long as this notice is included on all such materials and the materials are not sold, licensed, or otherwise distributed for commercial gain. Software Design Specification copyright © 1994-1997 by Bradford D. Appleton