This is a short document that describes some of the issues that confront a SMB implementation on unix, and how Samba copes with them. They may help people who are looking at unix<->PC interoperability. It was written to help out a person who was writing a paper on unix to PC connectivity. Andrew Tridgell April 1995 Usernames ========= The SMB protocol has only a loose username concept. Early SMB protocols (such as CORE and COREPLUS) have no username concept at all. Even in later protocols clients often attempt operations (particularly printer operations) without first validating a username on the server. Unix security is based around username/password pairs. A unix box should not allow clients to do any substantive operation without some sort of validation. The problem mostly manifests itself when the unix server is in "share level" security mode. This is the default mode as the alternative "user level" security mode usually forces a client to connect to the server as the same user for each connected share, which is inconvenient in many sites. In "share level" security the client normally gives a username in the "session setup" protocol, but does not supply an accompanying password. The client then connects to resources using the "tree connect" protocol, and supplies a password. The problem is that the user on the PC types the username and the password in different contexts, unaware that they need to go together to give access to the server. The username is normally the one the user typed in when they "logged onto" the PC (this assumes Windows for Workgroups). The password is the one they chose when connecting to the disk or printer. The user often chooses a totally different username for their login as for the drive connection. Often they also want to access different drives as different usernames. The unix server needs some way of divining the correct username to combine with each password. Samba tries to avoid this problem using several methods. These succeed in the vast majority of cases. The methods include username maps, the service%user syntax, the saving of session setup usernames for later validation and the derivation of the username from the service name (either directly or via the user= option). File Ownership ============== The commonly used SMB protocols have no way of saying "you can't do that because you don't own the file". They have, in fact, no concept of file ownership at all. This brings up all sorts of interesting problems. For example, when you copy a file to a unix drive, and the file is world writeable but owned by another user the file will transfer correctly but will receive the wrong date. This is because the utime() call under unix only succeeds for the owner of the file, or root, even if the file is world writeable. For security reasons Samba does all file operations as the validated user, not root, so the utime() fails. This can stuff up shared development diectories as programs like "make" will not get file time comparisons right. There are several possible solutions to this problem, including username mapping, and forcing a specific username for particular shares. Passwords ========= Many SMB clients uppercase passwords before sending them. I have no idea why they do this. Interestingly WfWg uppercases the password only if the server is running a protocol greater than COREPLUS, so obviously it isn't just the data entry routines that are to blame. Unix passwords are case sensitive. So if users use mixed case passwords they are in trouble. Samba can try to cope with this by either using the "password level" option which causes Samba to try the offered password with up to the specified number of case changes, or by using the "password server" option which allows Samba to do it's validation via another machine (typically a WinNT server). Samba also doesn't support the password encryption method used by SMB clients. This is because the spec isn't sufficiently detailed for an implementation (although Jeremy Allison is working on it, to try and work it out). Also, there is a fundamental problem with what we understand so far in the algorithm, as it seems that the server would need to store somewhere on disk a reversibly encrypted (effectively plaintext) copy of the users password in order to use the algorithm. This goes against the unix policy that "even the super-user doesn't know your password" which comes from the use of a one-way hash function. Locking ======= The locking calls available under a DOS/Windows environment are much richer than those available in unix. This means a unix server (like Samba) choosing to use the standard fcntl() based unix locking calls to implement SMB locking has to improvise a bit. One major problem is that dos locks can be in a 32 bit (unsigned) range. Unix locking calls are 32 bits, but are signed, giving only a 31 bit range. Unfortunately OLE2 clients use the top bit to select a locking range used for OLE semaphores. To work around this problem Samba compresses the 32 bit range into 31 bits by appropriate bit shifting. This seems to work but is not ideal. In a future version a separate SMB lockd may be added to cope with the problem. It also doesn't help that many unix lockd daemons are very buggy and crash at the slightest provocation. They normally go mostly unused in a unix environment because few unix programs use byte range locking. The stress of huge numbers of lock requests from dos/windows clients can kill the daemon on some systems. The second major problem is the "opportunistic locking" requested by some clients. If a client requests opportunistic locking then it is asking the server to notify it if anyone else tries to do something on the same file, at which time the client will say if it is willing to give up it's lock. Unix has no simple way of implementing opportunistic locking, and currently Samba has no support for it. Deny Modes ========== When a SMB client opens a file it asks for a particular "deny mode" to be placed on the file. These modes (DENY_NONE, DENY_READ, DENY_WRITE, DENY_ALL, DENY_FCB and DENY_DOS) specify what actions should be allowed by anyone else who tries to use the file at the same time. If DENY_READ is placed on the file, for example, then any attempt to open the file for reading should fail. Unix has no equivalent notion. To implement these Samba uses lock files based on the files inode and placed in a separate lock directory. These are clumsy and consume processing and file resources, so they are optional and off by default. Trapdoor UIDs ============= A SMB session can run with several uids on the one socket. This happens when a user connects to two shares with different usernames. To cope with this the unix server needs to switch uids within the one process. On some unixes (such as SCO) this is not possible. This means that on those unixes the client is restricted to a single uid. Port numbers ============ There is a convention that clients on sockets use high "unprivilaged" port numbers (>1000) and connect to servers on low "privilaged" port numbers. This is enforced in Unix as non-root users can't open a socket for listening on port numbers less than 1000. Most PC based SMB clients (such as WfWg and WinNT) don't follow this convention completely. The main culprit is the netbios nameserving on udp port 137. Name query requests come from a source port of 137. This is a problem when you combine it with the common firewalling technique of not allowing incoming packets on low port numbers. This means that these clients can't query a netbios nameserver on the other side of a low port based firewall. The problem is more severe with netbios node status queries. I've found that WfWg, Win95 and WinNT3.5 all respond to netbios node status queries on port 137 no matter what the source port was in the request. This works between machines that are both using port 137, but it means it's not possible for a unix user to do a node status request to any of these OSes unless they are running as root. The answer comes back, but it goes to port 137 which the unix user can't listen on. Interestingly WinNT3.1 got this right - it sends node status responses back to the source port in the request. Protocol Complexity =================== There are many "protocol levels" in the SMB protocol. It seems that each time new functionality was added to a Microsoft operating system, they added the equivalent functions in a new protocol level of the SMB protocol to "externalise" the new capabilities. This means the protocol is very "rich", offering many ways of doing each file operation. This means SMB servers need to be complex and large. It also means it is very difficult to make them bug free. It is not just Samba that suffers from this problem, other servers such as WinNT don't support every variation of every call and it has almost certainly been a headache for MS developers to support the myriad of SMB calls that are available. There are about 65 "top level" operations in the SMB protocol (things like SMBread and SMBwrite). Some of these include hundreds of sub-functions (SMBtrans has at least 120 sub-functions, like DosPrintQAdd and NetSessionEnum). All of them take several options that can change the way they work. Many take d