SMBlib Discussion Paper V1.0
Preliminary
Copyright (C) Richard Sharpe 1996
4-Jan-1995

1 INTRODUCTION

In looking at developing a better understanding of SMB, NetBIOS, etc, I 
looked at implementing an SMB Library, so that programming SMB type 
applications, like a UNIX File Manager, SMBTAR, etc, would be relatively
easy by allowing the programmer to concentrate on their programming issues
and relieving them of having to implement SMB routines for each program.

I grabbed Client.c and talked to Andrew Tridgell, and came up with some 
routines and started to rip code out of client.c. Pretty soon, I came
up against a brick wall, because I wanted to do several things, like 
allow for support of NetBEUI and other protocols if possible (DECnet, 
X.25, etc). I also had questions about some of the functions I was 
going to implement and just what sort of functions were required.

So, I stepped back and took a stab at a design, which resulted 
in this document.

This is a discussion paper that sets down my ideas and solicits feedback on
mistakes and potential improvements. 

This document has been written as a simple text document to facilitate easy
reading of it, rather than have recipients uudecode or whatever and then read
in word.

1.1 Questions

a. Should I implement the NetBIOS API? There are many advantages of doing so.
   UNIX/LINUX users would gain access to NetBIOS servers out there. In 
   addition, it allows for support of many flavours or NetBIOS, eg RFCNB,
   IBMNB, NetBIOS over IPX, etc.

   An additional question here is: If we implement the NetBIOS API, should it
   be a library or a system call interface? Making it a library allows it to 
   be used on the widest range of UNIX platforms.


2 GOALS

The goals of this effort are:

1 Produce an SMB Library as specified below

2 Allow the SMB Library to communicate over TCP/IP (RFCNB) and NetBEUI
  if someone implements the NetBEUI code. This effort will implement
  the necessary RFCNB routines first. NetBEUI support will be considered 
  later, and perhaps only in those versions of UNIX where system call
  support for NetBEUI is provided.

3 Allow other protocols or transports to be easily grafted in.

4 Provide a sample SMBlib client application, in particular SMBprint, 
  a UNIX lpd(8) print filter that can send jobs to an SMB server for
  printing.

A non-goal at this stage is to have SAMBA use this library, as that would 
require radical change to the SAMBA code, I think (Andrew can correct me
on this), however, some tilts in SAMBA's direction have been included.

3 STRUCTURE

SMB stands for Server Message Block, and appears to be a protocol that
allows a client (typically a PC running DOS, Windows (including WfWg),
Win95 or Windows NT) to get a server to provide file and print access
as well as IPC and a few other bits and pieces. It is specified in a 
number of documents from Microsoft and perhaps others: Microsoft 
Networks/OpenNET FILE SHARING PROTOCOL, etc.

It soon became obvious, and in any case, good programming practice 
dictates, that a layered structure was going to be needed, to separate
the SMB part of the protocol out from the underlying transports and 
protocols.

In current implementations, SMB uses NetBIOS as the transport, with all
its attendant uglyness (cf NetBIOS name space management versus DNS).

There appears to be two implementations of NetBIOS: RFCNB as specified
in RFC1001 and RFC1002; and IBM NetBIOS (sometimes refered to as NetBEUI
as far as I can tell) as specified in various IBM documents (see IBM 
document SC30-3587-00: LAN Technical Reference, _IEEE 802.2 and NETBIOS
Application Program Interfaces_, esp Ch 5: The NETBIOS Fames Protocol
for details of the frame format).

I will refer to these as RFCNB and IBMNB.

Unfortunately, these two implementations of NetBIOS differ markedly in
frame formats, command codes, etc, and so would appear to be two 
different transports. This may be the result of NetBIOS being regarded
as an API.

The structure that I envision for this effort is depicted below:


   Client            SMBlib                        Server

  +-----------+-------------+                    +-----------+
  |           |             |                    |           |
  | Client    | Library     |                    | Server    |
  | Program   | Routines    +--------------------| Program   |
  |           |             | Network Connection |           |
  +-----------+-------------+                    +-----------+

Every effort will be made to allow a single client have multiple SMB 
sessions open to the same or different servers (in support of a file 
manager etc).

And for the SMBlib itself:


     +------------------------------------------------------+
     |                    SMB Layer                         |
     |                                                      |
     | Provides all SMBlib routines and makes use of        |
     | transport routines for communications                |
     |                                                      |
     +------------------------------------------------------+
     |                  Transport Layer                     |
     +-------------------------------+----------------------+
     |        NetBIOS Layer          |                      |
     |  RFCNB Layer  |  IBMNB Layer  |  Raw Protocol Layer  |
     |               |               |                      |
     +---------------+---------------+----------------------+
     |               |               |                      |
     | TCP/IP or     | DLC Layer?    | TCP/IP or X.25 or    |
     | Layer         |               | DECnet layer?        |
     |               |               |                      |
     +---------------+---------------+----------------------+

At the transport layer, one could use NetBIOS as a transport, or if 
implemented, one could use a Raw Protocol Layer. This is because, as 
discussed below, the functions of NetBIOS are to manage names and sessions,
something that TCP/IP does very well. 

Since most protocols (eg TCP/IP) provide these functions, it would seem that
SMB packets could be sent directly over TCP/IP. As there seems to be at 
least one person who is interested in writing a DOS redirector, they might
be interested in the above option. (A tcp port could be defined for SMB over 
TCP as apposed to SMB over RFCNB over TCP/IP, or alternatively, a protocol
for negotiating SMB over TCP/IP raw or over RFCNB could be defined--something
that looks like a protocol error to existing implementations for example, 
which would allow the client to try SMB over TCP/IP before falling back to 
SMB over RFCNB.

Now, service names look like \\server\service, and there seems no reason 
that the following sort of names should not be supported:

	\\NBSERVER\service		'NetBIOS SERVER name
	\\15.22.111.5\service		'IP Address for Server
	\\samba.anu.edu.au\service	'DNS name for server

In addition, both "/" and "\" should be acceptable as directory path i
separators.

The functions provided by each layer will be discussed in the following 
sections.

4 SMB LAYER

4.1 Error Handling

Client programs need to be aware of errors occuring in the SMB layer or 
in lower layers. SMB already has a notion of an error class and an error 
code, so an error structure needs to be kept around and routines are needed
to print our error messsages for client programs.

However, there can be sources of errors other than the SMB server 
implementation or the local SMB routines. For example, there might errors 
encountered in the transport layer relating to lack of resources or host
unreachable which can be reported to the client program, rather than 
reporting a catchall SMB error, like ERRgeneral.

I thought of extending the error classes as specified in the documentation
to include extra ones, like ERRTRAN etc for transport level errors, but the
problem with this is that MS might at any stage make their own extensions 
that conflict with my extensions.

I think that something like the following is needed for errors:

  typedef enum SMBE_enum {SMBE_None, SMBE_Trans, SMBE_NB, SMBE_SMB};

  typedef struct SMB_Error {

    SMBE_enum err_type;           /* Error Type  */
    int err_class;                /* Error Class */
    int err_code;                 /* Error Code  */
  };

With UNIX type errno values being plugged into err_code when relevant.

4.2 SMB Routines

The SMB layer provides a set of functions to client programs that allow 
services provided by SMB servers to be easily coded for. The functions and
general approach to using the library are given below.

This layer will use the functions in the transport layer for connecting to 
servers, and sending and receiving data.

Almost all functions will supply a pointer to an SMB structure that maintains
any state information that is needed. The client code will see this as a void *
and will not have any visibility into the structure.

The following functions are defined.

4.2.1 SMB_Print_Error

This routine will retrieve the most recent error, and print the appropriate 
error message. 

4.2.2 SMB_Init

This routine will initialize the SMB library, and might do things like 
instanciate each of the transport modules and initialize them. At the outset
we might be aware of more protocols that are actually implemented (eg, X.25,
RFCNB, IBMNB, IPXNB, TCP/IP (raw) etc) while only RFCNB is implemented.

There will also need to be ways to specify in which order the implemented
transports are tried when a connection is established.

It will also allocate all the top level structures needed by the library.

4.2.3 SMB_Connect

This routine will connect to an SMB server and service and log in as necessary.

Its general form will be:

  void * SMB_Connect(void *SMB_handle,
		     pstring service,
		     pstring username,
		     pstring password,
		     enum connection_type)

If it is called with SMB_Handle NULL, it will allocate an new SMB structure
and fill in all necessary values with defaults. However, if it is called with
al already existing SMB structure (non-NULL SMB_Handle) it will use the values
in the provided SMB structure.

This provides a mechanism for overiding defaults on a per SMB session basis. 
An example of the default you might wish to override is the order in which 
transports are tried to establish a connection.

4.2.4 SMB_Create

This routine will create an SMB structure and populate it with information from
the parameters passed (or perhaps separate routines will be provided to set 
values (to facilitate backward compatibility with clients built with shared
libraries when changes are made?).

4.2.5 SMB_Discon

This routine will disconnect from the the SMB server implied by the connection
structure in the SMB structure. It will call lower level transport routines
to do this.

4.2.6 SMB_Open

This routine will open a file on the server specified by the SMB structure 
passed as a parameter.

4.2.7 SMB_Close

This routine will close a file on the server specified by the SMB structure
passed as a parameter.

4.2.8 SMB_Logon

This routine will do an SMB logon to the server as specified by the SMB 
structure passed as a parameter. I am not sure if this routine is needed.

4.2.9 SMB_Read

This routine will read from the open file specified by the file handle passed
as a parameter.

4.2.10 SMB_Write

This routine will write to the open file specified by the file handle passed
as a parameter.

4.2.11 SMB_PWD

This routine will get the current working directory on the server specified 
by the SMB structure passed as a parameter.

4.2.12 SMB_CWD

This routine will change the current working directory on the server specified
by the SMB structure passed as a parameter.

4.2.13 SMB_ more routines

More routines will be defined, no doubt.

5 TRANSPORT LAYER

The function of the transport layer is to provide services/routines thah allow
the SMB layer to connect to and disconnect from an SMB server, to send data
to and receive data from an SMB server (on an already open connection) and to 
possibly wait for connections from an SMB client (a tilt at SAMBA).

Both RFCNB and IBMNB iprovide these services and seem to have two functions:

1.  Name space management. Setting the local station name and looking
    up the names of other stations (like servers) in order to set up
    sessions with them.

2.  Session management. Initiation of sessions, transmission of data 
    and termination of sessions.

The transport layer will make use of transport providers to handle these 
functions, and will use a defined interface to the transport providers so that
more transports can be easily plugged in at a later date.

The transport functions and the provider's interface are defined below.

5.1 Transport Functions

The following transport functions will be implemented.

5.1.1 TR_Connect

Connect to a server given the name of the server. Resolution of the name will
occur using the functions provided in the providers interface in the default
protocol order, unless this order has been overridden.

5.1.2 TR_Discon

Disconnect from the server. This will use the disconnect function provided by
the transport provider specified by the protocol indicated in the connection
structure passed as a parameter.

5.1.3 TR_Send

Send data over the connection.

5.1.4 TR_Recv

Receive data over the connection.

5.1.5 TR_Wait_For_Connection

Wait for a connection on a specified protocol?

5.1.6 TR_Get_Error

Return the text of the error message that last occurred for the connection or
transport.

5.1.7 TR_Init

Initialize the transport layer. In particular, initialize all of the protocols
available, pick up info about max data size, etc.

5.1.8 TR_Term

Terminat the transport layer. Tear down any connections that may be open and
generally clean up.

5.1.9 TR_Get_Session_Info

Pick up session info, like max data size, etc.

5.1.10 TR_Alloc_Packet

Allocate a packet for data transfer that takes into account any headers.

5.1.11 TR_Free_Packet

Free a packet.

5.2 Provider's Interface

The following routines are provided by the providers interface and must be 
provided by any protocol module.

5.2.1 <prot>_Connect

5.2.2 <prot>_Discon

5.2.3 <prot>_Send

5.2.4 <prot>_Recv

5.2.5 <prot>_Wait_For_Connection

5.2.6 <prot>_Get_Error

5.2.7 <prot>_Is_Implemented

Return a boolean with value True if the protocol is implemented, false
otherwise. If false is returned, all other routines above must be provided
and must return an error response if they are called. Error is TRE_Not_Impl.

5.2.8 <prot>_Init

5.2.9 <prot>_Term

5.2.10 <prot>_Get_Info

5.2.11 <prot>_Alloc_Packet

5.2.12 <prot>_Free_Packet

5.2.13 <prot>_Register_Name

Register a NetBIOS name if it is relevant to the protocol.

6 PACKET BUFFERS

All the above layers will be placing data into packets, and as we descend the
layers, data has to go into packet headers. For example:

 1  The SMB Layer places SMB\377 followed by SMB data in the packet
 2  The RFCNB layer places RFCNB send data header before the SMB data
 3  The packet is handed to the system level TCP/IP routines

So the generaized packet layout is:

  +---------------+-------------+--------------------------------------+
  | Transport Hdr | SMB Hdr     | User data of some sort               |
  +---------------+-------------+--------------------------------------+

and because of the various transports we are planning to use, the transport
header can vary in size, from 0 if we are using SMB over TCP/IP to 4 bytes if
we are using RFCNB (the session message packet header, see RFC1002), to 14 
bytes if we are using IBMNB (the DATA_FIRST_MIDDLE or DATA_ONLY_LAST packet
header, see the above cited IBM document). Of course, if IBMNB were to be
implemented as a system provided protocol with a system call interface, then
we will not have to worry about packet headers for it.

In order to allow each layer to work on the packets without data being copied 
a great many times as we descend layers, we need a packet format and allocation
scheme that allows packet of the right format to be allocated and worked on
regardless of underlying transport that is being used.

While one method that could be used is to maintain each header and the user 
data as separate fragments and link them all together, and to use calls like
readv and writev with an IOVEC, it is not clear that this is supported across
all OSes that this library might be implemented on (eg VMS). This method does
have the advantage of potentially removing the need to copy user data when 
it is passed to the SMBlib routines, as they can simply be linked into the
packet structure as the user data? However, if we have to fragment the user 
data, we may well have to copy anyway.

The method I propose to use is that each transport provider will provide
packet allocation routines that return a packet structure of:

  struct packet_struct {
    int user_data_offset;
    int max_user_data;
    char *data;
  }

Each allocation routine will be asked to allocate a packet of a certain size
and will add to that the size of the send data header that it will add.

This means that any macros or routines that manipulate SMB information will
have to be aware of this structure.
