Last revised: Jan 8, 2008
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.
The intended audience includes the PSARC review team, the OpenSolaris user community, our Quality Engineering staff and our Technical Writing staff.
Requirements: http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/cifs_client_prd.html
|
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 |
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.
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.
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.
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.
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.
No hard links - link(2) will return ENOSYS (hard links are not supported in the protocol dialects we speak)
No symlinks - symlink(2) will return ENOSYS (symbolic links are not supported in the protocol dialects we speak)
No real byte-range locks - fcntl(2) lock operations will be arbitrated locally (MI_LLOCK) (byte-range locks are not supported in the code base yet)
No ACLs set/get - GETACL with acl(2) and facl(2) will return a fabricated ACL like pcfs(7FS), SETACL will return ENOSYS (ACLs are not supported in the code base yet)
No device nodes - mknod(2) will return ENOSYS (device nodes are not supported in the protocol dialects we speak)
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

The following deliverables will be putback into Solaris Nevada, and possibly into a Solaris 10 update.
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).
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).
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.
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.
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.
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.xmlPSARC 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.
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.
|
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 |
We assume that there will be no interesting functional overlap with the CIFS server port in progress based on the Procom code base
We assume that this project will be suitable to backport to a Solaris 10 Update
We assume that the requirements and design are changeable, with appropriate review, as we learn new information
We assume that most users of the CIFS client will be accessing files on Windows machines and will not require access to Unix-specific objects such as symbolic links and devices
5.2 Goals and Guidelines
The KISS principle "Keep it simple Solaris!"
Organize design so we can develop with the OpenSolaris community
Limit initial functionality to basics and don't over promise
Product will work seamlessly with existing Solaris commands
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.
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 CIFS protocol was designed as a "remote" version of the user-level file API including: open, read, write, close, etc., while the Solaris VFS interface is designed to operate below the level of open instances. The Windows "redirector" gets control at a higher level (near the system call entry points), while the VFS works below the level of open file instances. One result of this fundamental mis-match is that there are few opportunities for sharing filesystem data structures across multiple users.
CIFS authentication is done at the connection/session level, while the VFS may present new credentials on any VOP call. Similarly, the user experience on Windows is that remote file shares are "mapped" (mounted) with a single set of credentials that apply to all access in that mount.
The VFS expects returned attributes to include owner/group and permissions (etc.) while the CIFS protocol operations normally used to get information about files and directories don't return any owner/group information. To access owner/group information, we need to fetch and process ACLs for each entry.
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:
We need to make sure that each distinct user doing an open gets a distinct vnode; this might look like the “specfs” cloneopen method, and permits us to make local open calls one-to-one with CIFS protocol opens.
We need to implement dynamic connection sharing such that each Unix user has at most one TCP connection to the server to comply with Windows licensing restrictions; connections would be closed when imactive and re-established on demand.
We need to create and store different CIFS “sessions” for each user in the CIFS private mount data such that we can find and use the correct session and TCP connection to use.
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.
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.
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.
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.
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) .
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.
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()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:
zone_key_create()
getzoneid()
zone_find_by_path()
zone_hold()
zone_rele()
zone_status_get()
zone_getspecific()
zone_setspecific()
zcmn_err()
zthread_create()
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.
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.
See man page(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/smbutil.1.txt)
mount_smbfs is the smbfs-specific mount utility called by mount(1M). It links with libsmbfs.so.
See man page(http://jurassic.eng/net/nfs-build/export1/projects/cifs/commitment.materials/mount_smbfs.1m.txt)
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'.
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 |
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. |
The smbfs module provides a VFS plugin to satisfy all filesystem operations on CIFS/SMB filesystems.
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'.
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. |
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). |
|
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. |
|
vop_shrlock |
smbfs_shrlock |
DOS-style share reservations, not supported in phase 1. |
|
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 |
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'.
|
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) |
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);
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.
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