]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Major rewrite of proxy authentication to support other schemes than
authorhno <>
Mon, 8 Jan 2001 06:32:04 +0000 (06:32 +0000)
committerhno <>
Mon, 8 Jan 2001 06:32:04 +0000 (06:32 +0000)
Basic (auth_rewrite branch on SourceForge).
Contributors:
   Andy Doran
   Robert Collins
   Chemolli Francesco
   Henrik Nordstrom

For details about the new API's, see Programmers Guide.

As part of this change everything from auth_modules has been moved to
src/auth/basic/helpers

131 files changed:
ChangeLog
configure.in
doc/Programming-Guide/prog-guide.sgml
doc/debug-sections.txt
helpers/basic_auth/LDAP/Makefile.in [new file with mode: 0644]
helpers/basic_auth/LDAP/README [new file with mode: 0644]
helpers/basic_auth/LDAP/squid_ldap_auth.c [new file with mode: 0644]
helpers/basic_auth/MSNT/COPYING-2.0 [new file with mode: 0644]
helpers/basic_auth/MSNT/Makefile.in [new file with mode: 0644]
helpers/basic_auth/MSNT/README.html [new file with mode: 0644]
helpers/basic_auth/MSNT/allowusers.c [new file with mode: 0644]
helpers/basic_auth/MSNT/byteorder.h [new file with mode: 0644]
helpers/basic_auth/MSNT/confload.c [new file with mode: 0644]
helpers/basic_auth/MSNT/denyusers.c [new file with mode: 0644]
helpers/basic_auth/MSNT/md4.c [new file with mode: 0644]
helpers/basic_auth/MSNT/msntauth-v2.0.lsm [new file with mode: 0644]
helpers/basic_auth/MSNT/msntauth.c [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-common.h [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-error.h [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-io.c [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-io.h [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-priv.h [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-util.c [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb-util.h [new file with mode: 0644]
helpers/basic_auth/MSNT/rfcnb.h [new file with mode: 0644]
helpers/basic_auth/MSNT/session.c [new file with mode: 0644]
helpers/basic_auth/MSNT/smbdes.c [new file with mode: 0644]
helpers/basic_auth/MSNT/smbencrypt.c [new file with mode: 0644]
helpers/basic_auth/MSNT/smblib-common.h [new file with mode: 0644]
helpers/basic_auth/MSNT/smblib-priv.h [new file with mode: 0644]
helpers/basic_auth/MSNT/smblib-util.c [new file with mode: 0644]
helpers/basic_auth/MSNT/smblib.c [new file with mode: 0644]
helpers/basic_auth/MSNT/smblib.h [new file with mode: 0644]
helpers/basic_auth/MSNT/std-defines.h [new file with mode: 0644]
helpers/basic_auth/MSNT/std-includes.h [new file with mode: 0644]
helpers/basic_auth/MSNT/valid.c [new file with mode: 0644]
helpers/basic_auth/MSNT/valid.h [new file with mode: 0644]
helpers/basic_auth/Makefile.in [new file with mode: 0644]
helpers/basic_auth/NCSA/Makefile.in [new file with mode: 0644]
helpers/basic_auth/NCSA/ncsa_auth.c [new file with mode: 0644]
helpers/basic_auth/PAM/Makefile.in [new file with mode: 0644]
helpers/basic_auth/PAM/pam_auth.c [new file with mode: 0644]
helpers/basic_auth/SMB/COPYING-2.0 [new file with mode: 0644]
helpers/basic_auth/SMB/Makefile.in [new file with mode: 0644]
helpers/basic_auth/SMB/README [new file with mode: 0644]
helpers/basic_auth/SMB/smb_auth.c [new file with mode: 0644]
helpers/basic_auth/SMB/smb_auth.sh [new file with mode: 0644]
helpers/basic_auth/YP/Makefile.in [new file with mode: 0644]
helpers/basic_auth/YP/nis_support.c [new file with mode: 0644]
helpers/basic_auth/YP/yp_auth.c [new file with mode: 0644]
helpers/basic_auth/getpwnam/Makefile.in [new file with mode: 0644]
helpers/basic_auth/getpwnam/getpwnam_auth.c [new file with mode: 0644]
helpers/basic_auth/multi-domain-NTLM/README.txt [new file with mode: 0644]
helpers/basic_auth/multi-domain-NTLM/smb_auth.pl [new file with mode: 0644]
helpers/ntlm_auth/Makefile.in [new file with mode: 0644]
helpers/ntlm_auth/SMB/Makefile.in [new file with mode: 0644]
helpers/ntlm_auth/SMB/libntlmssp.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/ntlm.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/ntlm_auth.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/Makefile.in [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/byteorder.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/md4.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/md4.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-common.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-error.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-io.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-io.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-priv.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-util.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb-util.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/rfcnb.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/session.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smbdes.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smbdes.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smbencrypt.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smbencrypt.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smblib-common.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smblib-priv.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smblib-util.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smblib.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/smblib.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/std-defines.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/std-includes.h [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/valid.c [new file with mode: 0644]
helpers/ntlm_auth/SMB/smbval/valid.h [new file with mode: 0644]
helpers/ntlm_auth/fakeauth/Makefile.in [new file with mode: 0644]
helpers/ntlm_auth/fakeauth/fakeauth_auth.c [new file with mode: 0644]
helpers/ntlm_auth/fakeauth/ntlm.h [new file with mode: 0644]
helpers/ntlm_auth/no_check/Makefile.in [new file with mode: 0644]
helpers/ntlm_auth/no_check/README.no_check_ntlm_auth [new file with mode: 0644]
include/ntlmauth.h [new file with mode: 0644]
include/util.h
lib/Makefile.in
lib/base64.c
lib/ntlmauth.c [new file with mode: 0644]
lib/util.c
src/HttpRequest.cc
src/Makefile.in
src/access_log.cc
src/acl.cc
src/auth/Makefile.in [new file with mode: 0644]
src/auth/basic/Makefile.in [new file with mode: 0644]
src/auth/basic/auth_basic.cc [new file with mode: 0644]
src/auth/basic/auth_basic.h [new file with mode: 0644]
src/auth/ntlm/Makefile.in [new file with mode: 0644]
src/auth/ntlm/auth_ntlm.cc [new file with mode: 0644]
src/auth/ntlm/auth_ntlm.h [new file with mode: 0644]
src/auth_modules.sh [new file with mode: 0644]
src/authenticate.cc
src/cache_cf.cc
src/cbdata.cc
src/cf.data.pre
src/client_side.cc
src/defines.h
src/enums.h
src/errorpage.cc
src/forward.cc
src/ftp.cc
src/globals.h
src/helper.cc
src/http.cc
src/main.cc
src/mem.cc
src/protos.h
src/redirect.cc
src/ssl.cc
src/stat.cc
src/structs.h
src/tools.cc
src/tunnel.cc
src/typedefs.h

index 659fe13ed467ac33dbe0a0fea4e3971e70fac109..7023a4279c070927ef0778d42b9c85e6f434ec4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 
 Changes to squid-2.5
+       - Major rewrite of proxy authentication to support other schemes
+         than basic. First in the line is NTLM support but others can
+         easily be added (digest is on the way). See Programmers Guide.
+         (Robert Collins & Chemolli Francesco)
+       - Reworked how request bodies are passed down to the protocols.
+         Now all client side processing is inside client_side.c, and
+         the pass and pump modules is no longer used.
        - Optimized searching in proxy_auth and ident ACL types. Should
          now handle large access lists a lot more efficient.
          (Francesco Chemolli)
index 5589768aa3fad40027cd2b1e306a69c7579cf6ad..885b32fda5067e16fcfec86e926cc06499acc5d4 100644 (file)
@@ -3,13 +3,13 @@ dnl  Configuration input file for Squid
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.211 2001/01/04 21:53:57 hno Exp $
+dnl  $Id: configure.in,v 1.212 2001/01/07 23:36:27 hno Exp $
 dnl
 dnl
 dnl
 AC_INIT(src/main.c)
 AC_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.211 $)dnl
+AC_REVISION($Revision: 1.212 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AC_CONFIG_AUX_DIR(cfgaux)
 
@@ -615,7 +615,6 @@ AC_ARG_ENABLE(leakfinder,
 ])
 AC_SUBST(LEAKFINDER_OBJS)
 
-dnl Disable HTTP violations
 AC_ARG_ENABLE(ident-lookups,
 [  --disable-ident-lookups
                           This allows you to remove code that performs
@@ -676,32 +675,117 @@ AC_ARG_ENABLE(underscores,
   fi
 ])
 
-dnl Select auth modules to build
-AUTH_MODULES=
+
+dnl Select auth schemes modules to build
+AC_ARG_ENABLE(auth,
+[  --enable-auth=\"list of auth scheme modules\"
+                          Build support for the list of authentication schemes.
+                          The default is to build support for the Basic scheme.
+                          See src/auth for a list of available modules, or
+                          Programmers Guide section authentication schemes
+                          for details on how to build your custom auth scheme
+                          module],
+[ case $enableval in
+  yes)
+        for module in $srcdir/src/auth/*; do
+            if test -f $module/Makefile.in; then
+                AUTH_MODULES="$AUTH_MODULES `basename $module`"
+            fi
+        done
+        ;;
+  no)
+        ;;
+  *)    AUTH_MODULES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+        ;;
+  esac
+],
+[ if test -z "$AUTH_MODULES"; then
+    AUTH_MODULES="basic"
+  fi
+])
+echo "Auth scheme modules built: $AUTH_MODULES"
+AC_SUBST(AUTH_MODULES)
+AUTH_OBJS="auth/`echo $AUTH_MODULES|sed -e's% %.a auth/%g'`.a"
+AC_SUBST(AUTH_OBJS)
+AUTH_LIBS="`echo $AUTH_OBJS|sed -e's%auth/%%g'`"
+AC_SUBST(AUTH_LIBS)
+
+dnl Select basic auth scheme helpers to build
+BASIC_AUTH_HELPERS=""
 AC_ARG_ENABLE(auth-modules,
-[  --enable-auth-modules=\"list of modules\"
-                          This option selects wich proxy_auth helper modules
-                          to build and install as part of the normal build
+[  --enable-auth-modules=\"list of helpers\"
+                          Backwards compability alias for
+                          --enable-basic-auth-helpers],
+[ echo "--enable-auth-modules is obsolete. Please use the new"
+  echo "option --enable-basic-auth-helpers"
+  sleep 5
+  case "$enableval" in
+  yes) 
+    for helper in $srcdir/src/auth/basic/helpers/*; do
+       if test -f $helper/Makefile.in; then
+           AUTH_BASIC_HELPERS="$AUTH_BASIC_HELPERS `basename $helper`"
+       fi
+    done
+    ;;
+  no)
+    ;;
+  *)
+    AUTH_BASIC_HELPERS="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+  esac
+])
+AC_ARG_ENABLE(basic-auth-helpers,
+[  --enable-basic-auth-helpers=\"list of helpers\"
+                          This option selects which basic scheme proxy_auth
+                          helpers to build and install as part of the normal 
+                          build process. For a list of available
+                          helpers see the src/auth/basic/helpers directory.],
+[ case "$enableval" in
+  yes) 
+    BASIC_AUTH_HELPERS=""
+    for helper in $srcdir/src/auth/basic/helpers/*; do
+       if test -f $helper/Makefile.in; then
+           AUTH_BASIC_HELPERS="$AUTH_BASIC_HELPERS `basename $helper`"
+       fi
+    done
+    ;;
+  no)
+    ;;
+  *)
+    AUTH_BASIC_HELPERS="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+  esac
+])
+if test -n "$AUTH_BASIC_HELPERS"; then
+    echo "Basic auth helpers built: $AUTH_BASIC_HELPERS"
+fi
+AC_SUBST(AUTH_BASIC_HELPERS)
+
+dnl Select ntlm auth helpers to build
+NTLM_AUTH_HELPERS=
+AC_ARG_ENABLE(ntlm-auth-helpers,
+[  --enable-ntlm-auth-helpers=\"list of helpers\"
+                          This option selects which proxy_auth ntlm helpers
+                          to build and install as part of the normal build 
                           process. For a list of available modules see
-                          the auth_modules directory.],
+                          the src/auth/ntlm/helpers directory.],
 [ case "$enableval" in
   yes) 
-    for module in $srcdir/auth_modules/*; do
-       if test -f $module/Makefile.in; then
-           AUTH_MODULES="$AUTH_MODULES `basename $module`"
+    for helper in $srcdir/src/auth/ntlm/helpers/*; do
+       if test -f $helper/Makefile.in; then
+           NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS `basename $helper`"
        fi
     done
     ;;
   no)
     ;;
   *)
-    AUTH_MODULES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+    NTLM_AUTH_HELPERS="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
   esac
 ])
-if test -n "$AUTH_MODULES"; then
-    echo "Auth moules built: $AUTH_MODULES"
+if test -n "$NTLM_AUTH_HELPERS"; then
+    echo "NTLM auth helpers built: $NTLM_AUTH_HELPERS"
 fi
-AC_SUBST(AUTH_MODULES)
+AC_SUBST(NTLM_AUTH_HELPERS)
+
 
 dnl Disable "unlinkd" code
 AC_ARG_ENABLE(unlinkd,
@@ -1710,13 +1794,33 @@ for repl in $REPL_POLICIES none; do
        fi
 done
 
-AUTH_MAKEFILES=""
-for module in $srcdir/auth_modules/*; do
-       if test -f $module/Makefile.in; then
-           AUTH_MAKEFILES="$AUTH_MAKEFILES ./auth_modules/`basename $module`/Makefile"
+AUTH_SCHEME_MAKEFILES=""
+for auth in $AUTH_MODULES none; do
+        if test $auth != none; then
+            AUTH_SCHEME_MAKEFILES="$AUTH_SCHEME_MAKEFILES ./src/auth/$auth/Makefile"
+        fi
+done
+
+BASIC_AUTH_MAKEFILES=""
+for helper in $srcdir/src/auth/basic/helpers/*; do
+       if test -f $helper/Makefile.in; then
+           BASIC_AUTH_MAKEFILES="$BASIC_AUTH_MAKEFILES ./src/auth/basic/helpers/`basename $helper`/Makefile"
        fi
 done
 
+NTLM_AUTH_MAKEFILES=""
+for helper in $srcdir/src/auth/ntlm/helpers/*; do
+        if test -f $helper/Makefile.in; then
+            NTLM_AUTH_MAKEFILES="$NTLM_AUTH_MAKEFILES ./src/auth/ntlm/helpers/`basename $helper`/Makefile"
+           for submodule in $helper/*; do
+               if test -f $submodule/Makefile.in; then
+                     NTLM_AUTH_MAKEFILES="$NTLM_AUTH_MAKEFILES ./src/auth/ntlm/helpers/`basename $helper`/`basename $submodule`/Makefile"
+               fi
+           done
+        fi
+done
+
+
 AC_OUTPUT(\
        ./makefile \
        ./lib/Makefile \
@@ -1729,10 +1833,14 @@ AC_OUTPUT(\
        $FS_MAKEFILES \
        ./src/repl/Makefile \
        $REPL_MAKEFILES \
+       ./src/auth/Makefile \
+       $AUTH_SCHEME_MAKEFILES \
+       ./src/auth/basic/helpers/Makefile \
+       $BASIC_AUTH_MAKEFILES \
+       ./src/auth/ntlm/helpers/Makefile \
+       $NTLM_AUTH_MAKEFILES \
        ./contrib/Makefile \
        $SNMP_MAKEFILE \
        ./icons/Makefile \
        ./errors/Makefile \
-       ./auth_modules/Makefile \
-       $AUTH_MAKEFILES \
 )
index 5c824505d18481cb5adfdf553e369559b0becea2..b5e3ce89b89ec352100ddcc5b84ba17a68e09789 100644 (file)
@@ -2,7 +2,7 @@
 <article>
 <title>Squid Programmers Guide</title>
 <author>Duane Wessels, Squid Developers
-<date>$Id: prog-guide.sgml,v 1.33 2001/01/06 11:39:43 hno Exp $</date>
+<date>$Id: prog-guide.sgml,v 1.34 2001/01/07 23:36:35 hno Exp $</date>
 
 <abstract>
 Squid is a WWW Cache application developed by the National Laboratory
@@ -153,6 +153,14 @@ Squid consists of the following major components
        information and continues the access control checks when
        the information is available.
 
+<sect1>Authentication Framework
+
+       <P>
+       These functions are responsible for handling HTTP authentication.
+       They follow a modular framework allow different auth schemes
+       to be added at will. For information on working with the auth schemes
+       See the chapter Authentication Framework.
+
 <sect1>Network Communication
 
        <P>
@@ -2011,6 +2019,343 @@ coupling between the storage layer and the replacement policy.
        <P>
        To be written...
 
+<!-- %%%% Chapter : Authentication Framework %%%% -->
+<sect>Authentication Framework
+
+       <P>
+        <enum>
+        <item>Definition of an auth scheme.
+        <item>Data types
+        <item>How to add a new auth scheme
+        <item>How to 'hook in' new functions to the API.</enum>
+               
+       <P>
+       Definition of an auth scheme
+               
+       <P>An auth scheme in squid is the collection of functions required to
+        manage the authentication process for a given HTTP authentication
+        scheme. Existing auth schemes in squid are Basic and NTLM. Other HTTP
+        schemes (see for example rfc 2617) have been published and could be
+        implemented in squid. The term auth scheme and auth module are
+        interchangable. An auth module is not to be confused with an
+        authentication helper, which is a scheme specific external program used
+        by a specific scheme to perform data manipulation external to squid.
+        Typically this involves comparing the browser submitted credentials with
+        those in the organisation's user directory.
+               
+       <P>Auth modules SHOULD NOT perform access control functions. Squid has
+        advanced caching access control functionality already. Future work in
+        squid will allow a auth scheme helper to return group information for a
+        user, to allow Squid to more seamlessly implement access control.
+               
+       <P>Data types
+               
+       <P>The data types are presented in C for the simple reason that squid is
+        currently written exclusively in C.
+               
+       <P>Function typedefs.
+       
+       <P>Each function related to the general case of http authentication has
+        a matching typedef. There are some additional function types used to
+        register/initialise, deregister/shutdown and provide stats on auth
+        modules:
+               
+       <P>typedef int   AUTHSACTIVE();
+               
+       <P>The Active function is used by squid to determine whether the auth
+        module has successfully configured and initialised itself. If Active
+        returns 0 no other module functions except Shutdown/Dump/Parse/FreeConfig
+       will be called by Squid.
+               
+       <P>typedef void  AUTHSSETUP(authscheme_entry_t *);
+               
+       <P>functions of type AUTHSSETUP are used to register an auth module with
+        squid. The registration function MUST be named
+        "authSchemeSetup_SCHEME" where SCHEME is the auth_scheme as
+        defined by rfc 2617. Only one auth scheme registered in squid can
+        provide functionality for a given auth_scheme. (I.e. only one auth
+        module can handle Basic, only one can handle Digest and so forth). The
+        Setup function is responsible for registering the functions in the
+        auth module into the passed authscheme_entry_t. The authscheme_entry_t
+        will never be NULL. If it is NULL the auth module should log an error
+        and do nothing. The other functions can have any desired name that does
+        not collide with any statically linked function name within Squid. It is
+        recommended to use names of the form "authe_SCHEME_FUNCTIONNAME" (for example
+        authenticate_NTLM_Active is the Active() function for the NTLM auth
+        module.
+               
+       <P>typedef void  AUTHSSHUTDOWN(void);
+               
+       <P>Functions of type AUTHSSHUTDOWN are responsible for freeing any
+        resources used by the auth modules. The shutdown function will be called
+        before squid reconfigures, and before squid shutsdown.
+               
+       <P>typedef void  AUTHSINIT(authScheme *);
+               
+       <P>Functions of type AUTHSINIT are responsible for allocating any
+        needed resources for the authentication module. AUTHSINIT functions are
+        called after each configuration takes place before any new requests are
+        made.
+               
+       <P>typedef void  AUTHSPARSE(authScheme *, int, char *);
+               
+       <P>Functions of type AUTHSPARSE are responsible for parsing
+        authentication parameters. The function currently needs a scheme scope
+        data structure to store the configuration in. The passed scheme's
+        scheme_data pointer should point to the local data structure. Future
+        development will allow all authentication schemes direct access to their
+        configuration data without a locally scope structure. The parse function
+        is called by squid's config file parser when a auth_param scheme_name
+        entry is encountered.
+               
+       <P>typedef void  AUTHSFREECONFIG(authScheme *);
+               
+       <P>Functions of type AUTHSFREECONFIG are called by squid when freeing
+        configuration data. The auth scheme should free any memory allocated
+        that is related to parse data structures. The scheme MAY take advantage
+        of this call to remove scheme local configuration dependent data. (Ie
+        cached user details that are only relevant to a config setting).
+               
+       <P>typedef void  AUTHSDUMP(StoreEntry *, const char *, authScheme *);
+               
+       <P>Functions of type AUTHSDUMP are responsible for writing to the
+        StoreEntry the configuration parameters that a user would put in a
+        config file to recreate the running configuration.
+               
+       <P>typedef void  AUTHSSTATS(StoreEntry *);
+        <P>Functions of type AUTHSSTATS are called by the cachemgr to provide
+        statistics on the authmodule. Current modules simply provide the
+        statistics from the back end helpers (number of requests, state of the
+        helpers), but more detailed statistics are possible - for example unique
+        users seen or failed authentication requests.
+        <P>The next set of functions work on the data structures used by the
+        authentication schemes.
+               
+       <P>typedef void  AUTHSREQFREE(auth_user_request_t *);
+       
+       <P>The AUTHSREQFREE function is called when a auth_user_request is being
+        freed by the authentication framework, and scheme specific data was
+        present. The function should free any scheme related data and MUST set
+        the scheme_data pointer to NULL. Failure to unlink the scheme data will
+        result in squid dieing.
+               
+       <P>typedef char *AUTHSUSERNAME(auth_user_t *);
+               
+       <P>Squid does not make assumptions about where the username is stored.
+        This function must return a pointer to a NULL terminated string to be
+        used in logging the request. Return NULL if no username/usercode is
+        known. The string should NOT be allocated each time this function is
+        called.
+               
+       <P>typedef int   AUTHSAUTHED(auth_user_request_t *);
+       
+       <P>The AUTHED function is used by squid to determine whether the auth
+        scheme has successfully authenticated the user request. If timeouts on
+        cached credentials have occured or for any reason the credentials are
+        not valid, return false.<P>The next set of
+        functions perform the actual authentication. The functions are used by
+        squid for both WWW- and Proxy- authentication. Therefore they MUST NOT
+        assume the authentication will be based on the Proxy-* Headers.
+               
+       <P>typedef void  AUTHSAUTHUSER(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type);
+        <P>Functions of type AUTHSAUTHUSER are called when Squid has a request
+        that needs authentication. If needed the auth scheme can alter the
+        auth_user pointer (usually to point to a previous instance of the user
+        whose name is discovered late in the auth process. For an example of
+        this see the ntlm scheme). These functions are responsible for
+        performing any in-squid routines for the authentication of the user. The
+        auth_user_request struct that is passed around is only persistent for
+        the current request. If the auth module requires access to the structure
+        in the future it MUST lock it, and implement some method for identifying
+        it in the future. For example the NTLM module implements a connection
+        based authentication scheme, so the auth_user_request struct gets
+        referenced from the ConnStateData.
+               
+       <P>typedef void  AUTHSDECODE(auth_user_request_t *, const char *);
+               
+       <P>Functions of type AUTHSDECODE are responsible for decoding the passed
+        authentication header, creating or linking to a auth_user struct and for
+        storing any needed details to complete authentication in AUTHSAUTHUSER.
+               
+       <P>typedef int   AUTHSDIRECTION(auth_user_request_t *);
+               
+       <P>Functions of type AUTHSDIRECTION are used by squid to determine what
+        the next step in performing authentication for a given scheme is. The
+        following are the return codes:
+        
+        -2 = error in the auth module. Cannot determine request direction.
+        -1 = the auth module needs to send data to an external helper.
+        Squid will prepare for a callback on the request and call the
+         AUTHSSTART function.
+         0 = the auth module has all the information it needs to
+           perform the authentication and provide a succeed/fail result.
+         1 = the auth module needs to send a new challenge to the
+         request originator. Squid will return the appropriate status code
+         (401 or 407) and call the registered FixError function to allow the
+         auth module to insert it's challenge.
+               
+       <P>typedef void  AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *);
+               
+       <P>Functions of type AUTHSFIXERR are used by squid to add scheme
+        specific challenges when returning a 401 or 407 error code. On requests
+        where no authentication information was provided, all registered auth
+        modules will have their AUTHSFIXERR function called. When the client
+        makes a request with an authentication header, on subsequent calls only the matching
+        AUTHSFIXERR function is called (and then only if the auth module
+        indicated it had a new challenge to send the client). If no auth schemes
+        match the request, the authentication credentials in the request are
+        ignored - and all auth modules are called.
+
+       <P>typedef void  AUTHSFREE(auth_user_t *);
+               
+       <P>These functions are responsible for freeing scheme specific data from
+        the passed auth_user_t structure. This should only be called by squid
+        when there are no outstanding requests linked to the auth user. This includes
+       removing the user from any scheme specific memory caches.
+               
+       <P>typedef void  AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int);
+        typedef void  AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int);
+               
+       <P>These functions are responsible for adding any authentication
+        specific header(s) or trailer(s) OTHER THAN the WWW-Authenticate and
+        Proxy-Authenticate headers to the passed HttpReply. The int indicates
+        whether the request was an accelerated request or a proxied request. For
+        example operation see the digest auth scheme. (Digest uses a
+        Authentication-Info header.) This function is called whenever a
+        auth_user_request exists in a request when the reply is constructed
+        after the body is sent on chunked replies respectively.
+               
+       <P>typedef void  AUTHSONCLOSEC(ConnStateData *);
+               
+       <P>This function type is called when a auth_user_request is
+        linked into a ConnStateData struct, and the connection is closed. If any
+        scheme specific activities related to the request or connection are in
+        progress, this function MUST clear them.
+               
+       <P>typedef void AUTHSSTART(auth_user_request_t * , RH * , void *);
+               
+       <P>This function type is called when squid is ready to put the request
+        on hold and wait for a callback from the auth module when the auth
+        module has performed it's external activities.
+               
+       <P>Structures
+               
+       <P>This is used to link auth_users into the username cache. Because some
+        schemes may link in aliases to a user, the link is not part of the
+        auth_user structure itself.
+               
+       <P>struct _auth_user_hash_pointer {
+    /* first two items must be same as hash_link */
+    char *key;
+    auth_user_hash_pointer *next;
+    auth_user_t *auth_user;
+    dlink_node link; /* other hash entries that point to the same auth_user */
+        };
+               
+       <P>This is the main user related structure. It stores user-related data,
+        and is persistent across requests. It can even persistent across
+        multiple external authentications. One major benefit of preserving this
+        structure is the cached acl match results. This structure, is private to
+        the authentication framework.
+               
+       <P>struct _auth_user_t {
+    /* extra fields for proxy_auth */
+    /* this determines what scheme owns the user data. */
+    auth_type_t auth_type;
+    /* the index +1 in the authscheme_list to the authscheme entry */
+    int auth_module;
+    /* we only have one username associated with a given auth_user struct */
+    auth_user_hash_pointer *usernamehash;
+    /* we may have many proxy-authenticate strings that decode to the same user*/
+    dlink_list proxy_auth_list;
+    dlink_list proxy_match_cache;
+    struct {
+    unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=failed*/
+    } flags;
+    long expiretime;
+    /* IP addr this user authenticated from */
+    struct in_addr ipaddr;
+    time_t ip_expiretime;
+    /* how many references are outstanding to this instance*/
+    size_t references;
+    /* the auth scheme has it's own private data area */
+    void *scheme_data;
+    /* the auth_user_request structures that link to this. Yes it could be a splaytree
+     * but how many requests will a single username have in parallel? */
+    dlink_list requests;
+        };
+               
+       <P>This is a short lived structure is the visible aspect of the
+        authentication framework.
+               
+       <P>struct _auth_user_request_t {
+    /* this is the object passed around by client_side and acl functions */
+    /* it has request specific data, and links to user specific data */
+    /* the user */
+    auth_user_t *auth_user;
+    /* return a message on the 401/407 error pages */
+    char *message;
+    /* any scheme specific request related data */
+    void *scheme_data;
+    /* how many 'processes' are working on this data */
+    size_t references;
+        };
+       
+        The authscheme_entry struct is used to store the runtime registered
+        functions that make up an auth scheme. An auth scheme module MUST implement
+        ALL functions except the
+        following functions: oncloseconnection, AddHeader, AddTrailer.. In
+        the future more optional functions may be added to this data type.
+               
+       <P>
+        struct _authscheme_entry {
+    char *typestr;
+    AUTHSACTIVE   *Active;
+    AUTHSADDHEADER *AddHeader;
+    AUTHSADDTRAILER *AddTrailer;
+    AUTHSAUTHED   *authenticated;
+    AUTHSAUTHUSER *authAuthenticate;
+    AUTHSDUMP     *dump;
+    AUTHSFIXERR   *authFixHeader;
+    AUTHSFREE     *FreeUser;
+    AUTHSFREECONFIG *freeconfig;
+    AUTHSUSERNAME *authUserUsername;
+    AUTHSONCLOSEC *oncloseconnection; /*optional*/
+    AUTHSDECODE   *decodeauth;
+    AUTHSDIRECTION *getdirection;
+    AUTHSPARSE    *parse;
+    AUTHSINIT     *init;
+    AUTHSREQFREE  *requestFree;
+    AUTHSSHUTDOWN *donefunc;
+    AUTHSSTART    *authStart;
+    AUTHSSTATS    *authStats;
+        };
+               
+       <P>For information on the requirements for each of the functions, see
+        the details under the typedefs above. For reference implementations, see
+        the squid source code, /src/auth/basic for a request based stateless auth module, and
+        /src/auth/ntlm for a connection based stateful auth module.
+       
+       <P>How to add a new auth scheme
+               
+       <P>Copy the nearest existing auth scheme and modify to recieve the
+        approprate scheme headers. Now step through the acl.c MatchAclProxyUser
+        function's code path and see how the functions call down through
+        authenticate.c to your scheme. Write a helper to provide you scheme with
+        any backend existence it needs. Remember any blocking code must go in
+        AUTHSSTART function(s) and _MUST_ use callbacks.
+               
+       <P>How to 'hook in' new functions to the API.
+               
+       <P>Start of by figuring the code path that will result in the function
+        being called, and what data it will need. Then create a typedef for the
+        function, add and entry to the authscheme_entry struct. Add a wrapper
+        function to authenticate.c (or if approprate cf_cache.c) that called the
+        scheme specific function if it exists. Test it. Test it again. Now
+        port to all the existing auth schemes, or at least add a setting
+        of NULL for the function for each scheme.
+
+
 <!-- %%%% Chapter : ICP %%%% -->
 <sect>ICP
 
index 1b35dbc6bcebf07b20d79f2007bcdfbc7824c247..b192ac07d23f9eda72f8690de44bcb7e5776118f 100644 (file)
@@ -33,7 +33,7 @@ section 25    MIME Parsing
 section 26    Secure Sockets Layer Proxy
 section 27    Cache Announcer
 section 28    Access Control
-section 29    Redirector
+section 29    Redirector & Authentication
 section 30    Ident (RFC 931)
 section 31    Hypertext Caching Protocol
 section 32    Asynchronous Disk I/O
diff --git a/helpers/basic_auth/LDAP/Makefile.in b/helpers/basic_auth/LDAP/Makefile.in
new file mode 100644 (file)
index 0000000..c697fa7
--- /dev/null
@@ -0,0 +1,76 @@
+
+OBJS           = squid_ldap_auth.o
+LIBS           = -lldap -llber
+LDAP_EXE       = squid_ldap_auth
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir     = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir  = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL           = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+all: $(LDAP_EXE)
+
+$(LDAP_EXE): $(OBJS)
+       $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(XTRA_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(libexecdir); then \
+               echo "mkdir $(libexecdir)"; \
+               mkdir $(libexecdir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(LDAP_EXE); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(libexecdir); \
+               $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) -f $(libexecdir)/-$$f; \
+               fi; \
+       done
+
+clean:
+       -$(RM) -f $(OBJS)
+       -$(RM) -f $(LDAP_EXE)
+
+distclean: clean
+       -$(RM) -f Makefile
diff --git a/helpers/basic_auth/LDAP/README b/helpers/basic_auth/LDAP/README
new file mode 100644 (file)
index 0000000..2af85db
--- /dev/null
@@ -0,0 +1,8 @@
+This LDAP Authentication code is written by Glen Newton
+<gnewton@wapiti.cisti.nrc.ca>.
+
+Please see his Web page at:
+http://orca.cisti.nrc.ca/~gnewton/opensource/squid_ldap_auth/
+
+In order to use squid_ldap_auth, you will also need to install
+the OpenLDAP libraries (ldap lber) from http://www.openldap.org.
diff --git a/helpers/basic_auth/LDAP/squid_ldap_auth.c b/helpers/basic_auth/LDAP/squid_ldap_auth.c
new file mode 100644 (file)
index 0000000..7f204d3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 
+ * squid_ldap_auth: authentication via ldap for squid proxy server
+ * 
+ * Author: Glen Newton 
+ * glen.newton@nrc.ca
+ * Advanced Services 
+ * CISTI
+ * National Research Council
+ * 
+ * Usage: squid_ldap_auth <ldap_server_name>
+ * 
+ * Dependencies: You need to get the OpenLDAP libraries
+ * from http://www.openldap.org
+ * 
+ * License: squid_ldap_auth is free software; you can redistribute it 
+ * and/or modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation; either version 2, 
+ * or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <lber.h>
+#include <ldap_cdefs.h>
+#include <ldap.h>
+
+/* Change this to your search base */
+#define SEARCHBASE "ou=people,o=nrc.ca"
+
+int checkLDAP(LDAP * ld, char *userid, char *password);
+
+int
+main(int argc, char **argv)
+{
+    char buf[256];
+    char *user, *passwd, *p;
+    char *ldapServer;
+    LDAP *ld;
+    LDAPMessage *result, *e;
+
+    setbuf(stdout, NULL);
+
+    if (argc != 2) {
+       fprintf(stderr, "Usage: squid_ldap_auth ldap_server_name\n");
+       exit(1);
+    }
+    ldapServer = (char *) argv[1];
+
+    while (fgets(buf, 256, stdin) != NULL) {
+       /* You can put this ldap connect outside the loop, but i didn't want to 
+        * have the connection open too much. If you have a site which will 
+        * be doing >1 authentication per second, you should move this (and the 
+        * below ldap_unbind()) outside the loop. 
+        */
+       if ((ld = ldap_init(ldapServer, LDAP_PORT)) == NULL) {
+           fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",
+               ldapServer, LDAP_PORT);
+           exit(1);
+       }
+       if ((p = strchr(buf, '\n')) != NULL)
+           *p = '\0';          /* strip \n */
+
+       if ((user = strtok(buf, " ")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       if ((passwd = strtok(NULL, "")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       if (checkLDAP(ld, user, passwd) != 0) {
+           printf("ERR\n");
+           continue;
+       } else {
+           printf("OK\n");
+       }
+       ldap_unbind(ld);
+    }
+}
+
+
+
+int
+checkLDAP(LDAP * ld, char *userid, char *password)
+{
+    char str[256];
+
+    /*sprintf(str,"uid=[%s][%s], %s",userid, password, SEARCHBASE); */
+    sprintf(str, "uid=%s, %s", userid, SEARCHBASE);
+
+    if (ldap_simple_bind_s(ld, str, password) != LDAP_SUCCESS) {
+       /*fprintf(stderr, "\nUnable to bind\n"); */
+       return 33;
+    }
+    return 0;
+}
diff --git a/helpers/basic_auth/MSNT/COPYING-2.0 b/helpers/basic_auth/MSNT/COPYING-2.0
new file mode 100644 (file)
index 0000000..d684351
--- /dev/null
@@ -0,0 +1,341 @@
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+        Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/helpers/basic_auth/MSNT/Makefile.in b/helpers/basic_auth/MSNT/Makefile.in
new file mode 100644 (file)
index 0000000..1252ecd
--- /dev/null
@@ -0,0 +1,98 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:44 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir      = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir   = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+AUTH_EXE       = msnt_auth$(exec_suffix)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL            = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+SNMPLIB                = @SNMPLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+DEFINES                = 
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = $(XTRA_LIBS)
+
+LIBPROGS        = $(AUTH_EXE)
+OBJS            = md4.o rfcnb-io.o rfcnb-util.o session.o msntauth.o \
+                 smbdes.o smbencrypt.o smblib-util.o smblib.o \
+                 valid.o denyusers.o allowusers.o confload.o
+
+all:    $(AUTH_EXE)
+
+$(AUTH_EXE): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(libexecdir); then \
+               echo "mkdir $(libexecdir)"; \
+               mkdir $(libexecdir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(LIBPROGS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(libexecdir); \
+               $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) -f $(libexecdir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *.a *pure_* core $(LIBPROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+tags:
+       ctags *.[ch]
+
+depend:
+       $(MAKEDEPEND) -fMakefile *.c
diff --git a/helpers/basic_auth/MSNT/README.html b/helpers/basic_auth/MSNT/README.html
new file mode 100644 (file)
index 0000000..6ac18ed
--- /dev/null
@@ -0,0 +1,317 @@
+<HTML>
+<HEAD>
+<TITLE>MSNTAUTH readme</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<!--
+If you require this document in text form, download the 
+HTML-text package from http://members.tripod.com/~stellarx.
+-->
+
+<H1>
+MSNT Auth v2.0.1<BR>
+Squid web proxy Authentication module<BR>
+Antonino Iannella, Stellar-X Pty Ltd<BR>
+Fri Sep 29 15:53:33 CST 2000
+</H1>
+
+<H2>Contents</H2>
+
+<UL>
+<LI> <A HREF="#introduction">Introduction</A>
+<LI> <A HREF="#installation">Installation</A>
+<LI> <A HREF="#compiling">Other compiling issues</A>
+<LI> <A HREF="#configuration">Configuration file</A>
+<LI> <A HREF="#denying">Denying users</A>
+<LI> <A HREF="#allowing">Allowing users</A>
+<LI> <A HREF="#squid">Squid.conf changes</A>
+<LI> <A HREF="#testing">Testing</A>
+<LI> <A HREF="#contact">Contact details</A>
+<LI> <A HREF="#reported">Reported problem</A>
+<LI> <A HREF="#known">Known limitation</A>
+<LI> <A HREF="#changes">Changes since last revision</A>
+</UL>
+
+<A NAME="introduction"><H2>Introduction</H2>
+
+<P>
+This is an authentication module for the Squid proxy server
+to authenticate users on an NT domain.
+
+<P>
+It originates from the Samba and SMB packages by Andrew Tridgell
+and Richard Sharpe. This version is sourced from the Pike
+authentication module by William Welliver (hwellive@intersil.com).
+
+<P>
+Usage is simple. It accepts a username and password on standard input
+and will return OK if the username/password is valid for the domain,
+or ERR if there was some problem.
+Check syslog messages for reported problems.
+
+<P>
+Msntauth is released under the GNU General Public License and
+is available from http://stellarx.tripod.com.
+
+<A NAME="installation"><H2>Installation</H2>
+
+<P>
+Make any changes to the source code you need.
+
+<P>
+Type 'make', then 'make install', then 'make clean'.
+
+<P>
+To avoid using the makefile, it may compile with
+
+  gcc -O2 -s -o msntauth *.c
+
+<P>
+'Make install' will put 'msntauth' into
+/usr/local/squid/bin by default.
+
+<P>
+Hopefully nobody has problems compiling msntauth.
+In the future I plan to use GNU automake.
+
+<A NAME="compiling"><H2>Other compiling issues</H2>
+
+<P>
+The Makefile uses the GCC compiler, and assumes that it is in the current PATH.
+Msntauth is known to compile properly on Redhat Linux 6, and FreeBSD 3.1
+without problems. Other operating systems are untested,
+but use a recent copy of the GNU C compiler.
+Smbencrypt.c has the '#include <sys/vfs.h>' line commented out.
+Remove the comment for S5R4 systems, like Solaris.
+
+<P>
+When compiling under Solaris, the socket libraries must be linked to.
+In the Makefile, hash the default CFLAGS line, and unhash the Solaris
+CFLAGS line. It always helps to have /usr/ccs/bin in your path
+prior to compiling.
+
+<A NAME="configuration"><H2>Configuration file</H2>
+
+<P>
+Msntauth uses a configuration file which is a break from previous
+releases. The file is /usr/local/squid/etc/msntauth.conf.
+If this needs to be changed, it is defined in confload.h.
+
+<P>
+An example configuration file is provided. It looks like
+
+<PRE>
+# Sample MSNT authenticator configuration file
+# Antonino Iannella, Stellar-X Pty Ltd
+# Tue Sep 26 17:26:59 CST 2000
+
+server my_PDC           my_BDC          my_NTdomain
+server other_PDC        other_BDC       otherdomain
+
+denyusers       /usr/local/squid/etc/denyusers
+allowusers      /usr/local/squid/etc/allowusers
+</PRE>
+
+<P>
+All comments start with '#'.
+
+<P>
+NT servers are used to query user accounts. The 'server' lines
+are used for this, with the PDC, BDC, and NT domain as parameters.
+Up to 5 servers/domains can be queried. If this is not enough
+modify the MAXSERVERS define in confload.h.
+At least one server must be specified, or msntauth will not
+run.
+
+<P>
+When a user provides a username/password, each of these
+servers will be queried to authenticate the username.
+It stops after a user has been successfully authenticated,
+so it makes sense to specify the most commonly queried
+server first. Make sure the servers can be reached and
+are active, or else msntauth will start failing user accounts!
+
+<P>
+The 'denyusers' and 'allowusers' lines give the absolute path
+to files of user accounts. They can be used to deny or allow
+access to the proxy. Do not use these directives if you
+do not need these features.
+
+<A NAME="denying"><H2>Denying users</H2>
+
+<P>
+Users who are not allowed to access the web proxy can be added to
+the denied user list. This list is read around every minute, or when
+the msntauth process receives a SIGHUP signal.
+
+<P>
+The denied user file is set using the 'denyusers' directive
+in msntauth.h.  The denied user file
+contains a list of usernames in no particular structure or form.
+If the file does not exist, no users are denied.
+The file must be readable by the web proxy user.
+
+<P>
+Msntauth will send syslog messages if a user was denied,
+at LOG_USER facility.
+
+<A NAME="allowing"><H2>Allowing users</H2>
+
+<P>
+Similar to denying users, you can allow users to access the proxy
+by username. This is useful if only a number of people are
+allowed supposed to be accessing a proxy.
+
+<P>
+The allowed user file is set using the 'allowusers' directive
+in msntauth.h.
+If the file does not exist or if empty, all users are allowed.
+
+<P>
+You could make use of the SHOWMBRS tool in Microsoft Technet.
+This gives you a list of users which are in a particular
+NT Domain Group. This list can be made into the allowed users
+file.
+
+<P>
+Some other rules -
+
+<OL>
+<LI> The operation of the denied user file is independent of the
+allowed user file. The former file is checked first.
+<LI> You can use none, one, or both files.
+<LI> If a username appears in the denied user file, they will
+be denied, even if they are in the allowed user file.
+<LI> If a username is not in either file, they will be denied,
+because they have not been allowed.
+<LI> If the allowed user file is in use and is empty, all
+users will be allowed.
+</OL>
+
+<P>
+Hopefully this wasn't too confusing.
+
+<A NAME="squid"><H2>Squid.conf changes</H2>
+
+<P>
+Refer to Squid documentation for the required changes to squid.conf.
+You will need to set the following lines to enable authentication for
+your access list -
+
+<PRE>
+  acl <yourACL> proxy_auth REQUIRED
+  http_access allow password
+  http_access allow <yourACL>
+  http_access deny all
+
+</PRE>
+
+<P>
+You will also need to review the following directives -
+
+<PRE>
+  proxy_auth_realm enterprise web gateway
+  authenticate_program /usr/local/squid/bin/msntauth
+  authenticate_ttl 5
+  authenticate_children 20
+</PRE>
+
+<A NAME="testing"><H2>Testing</H2>
+
+<P>
+I strongly urge that Msntauth is tested prior to being used in a 
+production environment. It may behave differently on different platforms.
+To test it, run it from the command line. Enter username and password
+pairs separated by a space.
+
+<P>
+It should behave in the following way -
+<PRE>
+ - Press ENTER to get an OK or ERR message.
+ - Make sure pressing CTRL-D behaves the same as a carriage return.
+ - Make sure pressing CTRL-C aborts the program.
+ - Test that entering no details does not result in an OK or ERR message.
+ - Test that entering an invalid username and password results in
+   an ERR message. Note that if NT guest user access is allowed on
+   the PDC, an OK message may be returned instead of ERR.
+ - Test that entering an valid username and password results in an OK message.
+   Try usernames which are and aren't in the denied/allowed user files,
+   if they're in use.
+ - Test that entering a guest username and password returns the correct response.
+</PRE>
+
+<P>
+If the above didn't work as expected, you may need to modify the main()
+function in msntauth.c. Inform the maintainer of any problems.
+
+<A NAME="contact"><H2>Contact details</H2>
+
+<P>
+To contact the maintainer of this package, email Antonino Iannella
+at antonino@usa.net, antonino.iannella@usa.net, or
+antonino.iannella@camtech.com.au.
+
+<P>
+The latest version may be found on http://members.tripod.com/stellarx.
+It is also distributed as part of Squid.
+
+<A NAME="reported"><H2>Reported problem</H2>
+
+<P>
+For an unknown username, Msntauth returns OK.
+This is because the PDC returns guest access for unknown users,
+even if guest access is disabled.
+This problem was reported by Mr Vadim Popov (vap@iilsr.minsk.by).
+I am not able to replicate this.
+
+<P>
+The tested environment consisted of PDC on Windows NT 4, SP 6.
+Squid 2.3 and Msntauth was tested on SuSe, RedHat, and Debian Linux.
+A fix was provided in case you have this problem.
+Apply the provided patch before compiling, using
+
+<PRE>
+  patch smblib.c < smblib.c.patch
+</PRE>
+
+<A NAME="known"><H2>Known limitation</H2>
+
+<P>
+Usernames are checked if they are allowed or denied. If a username
+is found as a substring of a different username in these files, 
+the user will be affected somehow. For example, if 'jpeterman' has
+been explicitly denied in the denyusers file, then 'jpeter' who
+is trying to use the proxy, will be denied. If this causes anyone 
+any problems, then I'll fix it.
+
+<P>
+As of version 2.0.1, this problem has been fixed.
+
+<A NAME="changes"><H2>Changes since last revision</H2>
+
+<P>
+The following list of changes have been made to improve msntauth.
+I have not had a chance to do too much testing due
+to lack of resources. There should be no problems, though.
+
+<UL>
+<LI>Added many patches from Duane Wessels to stop compilation errors (?)
+<LI>Improved the main() function yet again
+<LI>Created a more informative Makefile
+<LI>Added an 'allowed users' feature to complement the 'denied users' feature
+<LI>Stopped the use of alarm() which was causing problems under Solaris
+<LI>Added more syslog messages for authentication problems
+<LI>Added the use of a configuration file, instead of hard-coding NT server details
+<LI>Allowed for querying multiple NT servers and domains (this was a hot issue)
+<LI>Changed README into an HTML document to improve readability
+<LI>Didn't make use of GNU autoconf. I will in future, I promise.
+<LI>Removed denied/allowed username substring search limitation.
+</UL>
+
+<P>
+Hopefully msntauth and Squid is now a more valuable product.
+Feel free to send me success or problem stories.
+
+</BODY>
+</HTML>
diff --git a/helpers/basic_auth/MSNT/allowusers.c b/helpers/basic_auth/MSNT/allowusers.c
new file mode 100644 (file)
index 0000000..42ebfe3
--- /dev/null
@@ -0,0 +1,192 @@
+
+/*
+ * allowusers.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines are to allow users attempting to use the proxy which
+ * have been explicitly allowed by the system administrator.
+ * The code originated from denyusers.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define NAMELEN     50         /* Maximum username length */
+
+/* Global variables */
+
+char *AllowedUsers;            /* Pointer to string of allowed users */
+off_t AllowUserSize;           /* Size of allowed users file */
+struct stat FileBuf;           /* Stat data buffer */
+time_t LastModTime;            /* Last allowed user file modification time */
+
+char Allowuserpath[MAXPATHLEN];        /* MAXPATHLEN defined in param.h */
+
+/* Function declarations */
+
+int Read_allowusers();
+int Check_ifuserallowed(char *);
+void Checkforchange();
+void Checktimer();
+
+/*
+ * Reads the allowed users file for all users to be permitted.
+ * Returns 0 if the user list was successfully loaded,
+ * and 1 in case of error.
+ * Logs any messages to the syslog daemon.
+ */
+
+int
+Read_allowusers()
+{
+    FILE *AFile;               /* Allowed users file pointer */
+    off_t APos = 0;            /* File counter */
+    char AChar;                        /* Character buffer */
+
+    /* Stat the file. If it does not exist, save the size as zero.
+     * Clear the allowed user string. Return. */
+    if (stat(Allowuserpath, &FileBuf) == -1) {
+       if (errno == ENOENT) {
+           LastModTime = (time_t) 0;
+           AllowUserSize = 0;
+           free(AllowedUsers);
+           AllowedUsers = malloc(sizeof(char));
+           AllowedUsers[0] = '\0';
+           return 0;
+       } else {
+           syslog(LOG_USER | LOG_ERR, strerror(errno));
+           return 1;
+       }
+    }
+    /* If it exists, save the modification time and size */
+    LastModTime = FileBuf.st_mtime;
+    AllowUserSize = FileBuf.st_size;
+
+    /* Handle the special case of a zero length file */
+    if (AllowUserSize == 0) {
+       free(AllowedUsers);
+       AllowedUsers = malloc(sizeof(char));
+       AllowedUsers[0] = '\0';
+       return 0;
+    }
+    /* Free and allocate space for a string to store the allowed usernames */
+    free(AllowedUsers);
+
+    if ((AllowedUsers = malloc(sizeof(char) * (AllowUserSize + 3))) == NULL) {
+       syslog(LOG_USER | LOG_ERR, "Read_allowusers: malloc(AllowedUsers) failed.");
+       return 1;
+    }
+    /* Open the allowed users file. Report any errors. */
+
+    if ((AFile = fopen(Allowuserpath, "r")) == NULL) {
+       syslog(LOG_USER | LOG_ERR, "Read_allowusers: Failed to open allowed user file.");
+       syslog(LOG_USER | LOG_ERR, strerror(errno));
+       return 1;
+    }
+    /* Read user names into the AllowedUsers string.
+     * Make sure each string is delimited by a space. */
+
+    AllowedUsers[APos++] = ' ';
+
+    while (!feof(AFile)) {
+       if ((AChar = fgetc(AFile)) == EOF)
+           break;
+       else {
+           if (isspace(AChar))
+               AllowedUsers[APos++] = ' ';
+           else
+               AllowedUsers[APos++] = toupper(AChar);
+       }
+    }
+
+    AllowedUsers[APos++] = ' ';
+    AllowedUsers[APos] = '\0';
+    fclose(AFile);
+    return 0;
+}
+
+/*
+ * Check to see if the username provided by Squid appears in the allowed
+ * user list. Returns 0 if the user was not found, and 1 if they were.
+ */
+
+int
+Check_ifuserallowed(char *ConnectingUser)
+{
+    static char CUBuf[NAMELEN + 1];
+    static int x;
+    static char AllowMsg[256];
+
+    /* If user string is empty, allow */
+    if (ConnectingUser[0] == '\0')
+       return 1;
+
+    /* If allowed user list is empty, allow all users.
+     * If no users are supposed to be using the proxy, stop squid instead. */
+    if (AllowUserSize == 0)
+       return 1;
+
+    /* Check if username string is found in the allowed user list.
+     * If so, allow. If not, deny. Reconstruct the username
+     * to have whitespace, to avoid finding wrong string subsets. */
+
+    sscanf(ConnectingUser, " %s ", CUBuf);
+    sprintf(CUBuf, " %s ", CUBuf);
+
+    for (x = 0; x <= strlen(CUBuf); x++)
+       CUBuf[x] = toupper(CUBuf[x]);
+
+    if (strstr(AllowedUsers, CUBuf) != NULL)
+       return 1;
+    else {                     /* If NULL, they are not allowed to use the proxy */
+       sprintf(AllowMsg, "Denied access to user '%s'.", CUBuf);
+       syslog(LOG_USER | LOG_ERR, AllowMsg);
+       return 0;
+    }
+}
+
+/*
+ * Checks if there has been a change in the allowed users file.
+ * If the modification time has changed, then reload the allowed user list.
+ * This function is called by the SIGHUP signal handler.
+ */
+
+void
+Check_forallowchange()
+{
+    struct stat ChkBuf;                /* Stat data buffer */
+
+    /* Stat the allowed users file. If it cannot be accessed, return. */
+
+    if (stat(Allowuserpath, &ChkBuf) == -1) {
+       if (errno == ENOENT) {
+           LastModTime = (time_t) 0;
+           AllowUserSize = 0;
+           free(AllowedUsers);
+           AllowedUsers = malloc(sizeof(char));
+           AllowedUsers[0] = '\0';
+           return;
+       } else {                /* Report error when accessing file */
+           syslog(LOG_USER | LOG_ERR, strerror(errno));
+           return;
+       }
+    }
+    /* If found, compare the modification time with the previously-recorded
+     * modification time.
+     * If the modification time has changed, reload the allowed user list.
+     * Log a message of its actions. */
+
+    if (ChkBuf.st_mtime != LastModTime) {
+       syslog(LOG_USER | LOG_INFO, "Check_forallowchange: Reloading allowed user list.");
+       Read_allowusers();
+    }
+}
diff --git a/helpers/basic_auth/MSNT/byteorder.h b/helpers/basic_auth/MSNT/byteorder.h
new file mode 100644 (file)
index 0000000..1856df9
--- /dev/null
@@ -0,0 +1,87 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB Byte handling
+ * Copyright (C) Andrew Tridgell 1992-1995
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BYTEORDER_H_
+#define _BYTEORDER_H_
+
+/*
+ * This file implements macros for machine independent short and 
+ * int manipulation
+ */
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+ * byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
+
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#if CAREFUL_ALIGNMENT
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+#else
+/* this handles things for architectures like the 386 that can handle
+ * alignment errors */
+/*
+ * WARNING: This section is dependent on the length of int16 and int32
+ * being correct 
+ */
+#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
+#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
+#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
+#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
+#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
+#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
+#endif
+
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+
+#endif /* _BYTEORDER_H_ */
diff --git a/helpers/basic_auth/MSNT/confload.c b/helpers/basic_auth/MSNT/confload.c
new file mode 100644 (file)
index 0000000..89018af
--- /dev/null
@@ -0,0 +1,235 @@
+
+/*
+ * confload.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines load the msntauth configuration file.
+ * It stores the servers to query, sets the denied and
+ * allowed user files, and provides the 
+ * authenticating function.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#define CONFIGFILE   "/usr/local/squid/etc/msntauth.conf"      /* Path to configuration file */
+#define DENYUSERSDEFAULT   "/usr/local/squid/etc/denyusers"
+#define ALLOWUSERSDEFAULT  "/usr/local/squid/etc/allowusers"
+
+#define MAXSERVERS 5           /* Maximum number of servers to query. This number can be increased. */
+#define NTHOSTLEN 65
+
+extern char Denyuserpath[MAXPATHLEN];  /* MAXPATHLEN defined in param.h */
+extern char Allowuserpath[MAXPATHLEN];
+
+typedef struct _ServerTuple {
+    char pdc[NTHOSTLEN];
+    char bdc[NTHOSTLEN];
+    char domain[NTHOSTLEN];
+} ServerTuple;
+
+ServerTuple ServerArray[MAXSERVERS];   /* Array of servers to query */
+int Serversqueried = 0;                /* Number of servers queried */
+
+/* Declarations */
+
+int OpenConfigFile();
+void ProcessLine(char *);
+void AddServer(char *, char *, char *);
+int QueryServers(char *, char *);
+int QueryServerForUser(int, char *, char *);
+extern int Valid_User(char *, char *, char *, char *, char *);
+
+
+/*
+ * Opens and reads the configuration file.
+ * Returns 0 on success, or 1 for error.
+ */
+
+int
+OpenConfigFile()
+{
+    FILE *ConfigFile;
+    char Confbuf[2049];                /* Line reading buffer */
+
+    /* Initialise defaults */
+
+    Serversqueried = 0;
+    strcpy(Denyuserpath, DENYUSERSDEFAULT);
+    strcpy(Allowuserpath, ALLOWUSERSDEFAULT);
+
+    /* Open file */
+    if ((ConfigFile = fopen(CONFIGFILE, "r")) == NULL) {
+       syslog(LOG_USER | LOG_ERR, "OpenConfigFile: Failed to open %s.", CONFIGFILE);
+       syslog(LOG_USER | LOG_ERR, strerror(errno));
+       return 1;
+    }
+    /* Read in, one line at a time */
+
+    while (!feof(ConfigFile)) {
+       Confbuf[0] = '\0';
+       fgets(Confbuf, 2049, ConfigFile);
+       ProcessLine(Confbuf);
+    }
+
+    /* Check that at least one server is being queried. Report error if not.
+     * Denied and allowed user files are hardcoded, so it's fine if they're
+     * not set in the confugration file. */
+
+    if (Serversqueried == 0) {
+       syslog(LOG_USER | LOG_ERR, "OpenConfigFile: No servers set in %s. At least one is needed.", CONFIGFILE);
+       return 1;
+    }
+    fclose(ConfigFile);
+    return 0;
+}
+
+/* Parses a configuration file line. */
+
+void
+ProcessLine(char *Linebuf)
+{
+    char *Directive;
+    char *Param1;
+    char *Param2;
+    char *Param3;
+
+    /* Ignore empty lines */
+    if (strlen(Linebuf) == 0)
+       return;
+
+    /* Break up on whitespaces */
+    if ((Directive = strtok(Linebuf, " \t\n")) == NULL)
+       return;
+
+    /* Check for a comment line. If found, stop . */
+    if (Directive[0] == '#')
+       return;
+
+    /* Check for server line. Check for 3 parameters. */
+    if (strcasecmp(Directive, "server") == 0) {
+       Param1 = strtok(NULL, " \t\n");
+       Param2 = strtok(NULL, " \t\n");
+       Param3 = strtok(NULL, " \t\n");
+
+       if ((Param1[0] == '\0') ||
+           (Param2[0] == '\0') ||
+           (Param3[0] == '\0')) {
+           syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'server' line needs PDC, BDC, and domain parameters.");
+           return;
+       }
+       AddServer(Param1, Param2, Param3);
+       return;
+    }
+    /* Check for denyusers line */
+    if (strcasecmp(Directive, "denyusers") == 0) {
+       Param1 = strtok(NULL, " \t\n");
+
+       if (Param1[0] == '\0') {
+           syslog(LOG_USER | LOG_ERR, "ProcessLine: A 'denyusers' line needs a filename parameter.");
+           return;
+       }
+       strcpy(Denyuserpath, Param1);
+       return;
+    }
+    /* Check for allowusers line */
+    if (strcasecmp(Directive, "allowusers") == 0) {
+       Param1 = strtok(NULL, " \t\n");
+
+       if (Param1[0] == '\0') {
+           syslog(LOG_USER | LOG_ERR, "ProcessLine: An 'allowusers' line needs a filename parameter.");
+           return;
+       }
+       strcpy(Allowuserpath, Param1);
+       return;
+    }
+    /* Reports error for unknown line */
+    syslog(LOG_USER | LOG_ERR, "ProcessLine: Ignoring '%s' line.", Directive);
+}
+
+/*
+ * Adds a server to query to the server array.
+ * Checks if the number of servers to query is not exceeded.
+ * Does not allow parameters longer than NTHOSTLEN.
+ */
+
+void
+AddServer(char *ParamPDC, char *ParamBDC, char *ParamDomain)
+{
+    if (Serversqueried + 1 > MAXSERVERS) {
+       syslog(LOG_USER | LOG_ERR, "ProcessLine: Ignoring '%s' server line; too many servers.", ParamPDC);
+       return;
+    }
+    Serversqueried++;
+    strncpy(ServerArray[Serversqueried].pdc, ParamPDC, NTHOSTLEN);
+    strncpy(ServerArray[Serversqueried].bdc, ParamBDC, NTHOSTLEN);
+    strncpy(ServerArray[Serversqueried].domain, ParamDomain, NTHOSTLEN);
+    ServerArray[Serversqueried].pdc[NTHOSTLEN - 1] = '\0';
+    ServerArray[Serversqueried].bdc[NTHOSTLEN - 1] = '\0';
+    ServerArray[Serversqueried].domain[NTHOSTLEN - 1] = '\0';
+}
+
+/*
+ * Cycles through all servers to query.
+ * Returns 0 if one server could authenticate the user.
+ * Returns 1 if no server authenticated the user.
+ */
+
+int
+QueryServers(char *username, char *password)
+{
+    int Queryresult = 1;       /* Default result is an error */
+    int x = 1;
+
+    while (x <= Serversqueried) {      /* Query one server. Change Queryresult if user passed. */
+       if (QueryServerForUser(x++, username, password) == 0) {
+           Queryresult = 0;
+           break;
+       }
+    }
+
+    return Queryresult;
+}
+
+/*
+ * Attempts to authenticate the user with one server.
+ * Logs syslog messages for different errors.
+ * Returns 0 on success, non-zero on failure.
+ */
+
+int
+QueryServerForUser(int x, char *username, char *password)
+{
+    int result = 1;
+
+    result = Valid_User(username, password, ServerArray[x].pdc,
+       ServerArray[x].bdc, ServerArray[x].domain);
+
+    switch (result) {          /* Write any helpful syslog messages */
+    case 0:
+       break;
+    case 1:
+       syslog(LOG_AUTHPRIV | LOG_INFO, "Server error when checking %s.", username);
+       break;
+    case 2:
+       syslog(LOG_AUTHPRIV | LOG_INFO, "Protocol error when checking %s.", username);
+       break;
+    case 3:
+       syslog(LOG_AUTHPRIV | LOG_INFO, "Authentication failed for %s.", username);
+    }
+
+    return result;
+}
+
+/* Valid_User return codes -
+ * 
+ * 0 - User authenticated successfully.
+ * 1 - Server error.
+ * 2 - Protocol error.
+ * 3 - Logon error; Incorrect password or username given.
+ */
diff --git a/helpers/basic_auth/MSNT/denyusers.c b/helpers/basic_auth/MSNT/denyusers.c
new file mode 100644 (file)
index 0000000..a339679
--- /dev/null
@@ -0,0 +1,249 @@
+
+/*
+ * denyusers.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ * 
+ * These routines are to block users attempting to use the proxy which
+ * have been explicitly denied by the system administrator.
+ * Routines at the bottom also use the allowed user functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define NAMELEN     50         /* Maximum username length */
+
+/* Global variables */
+
+char *DeniedUsers;             /* Pointer to string of denied users */
+off_t DenyUserSize;            /* Size of denied user file */
+struct stat FileBuf;           /* Stat data buffer */
+time_t LastModTime;            /* Last denied user file modification time */
+
+char Denyuserpath[MAXPATHLEN]; /* MAXPATHLEN defined in param.h */
+
+/* Function declarations */
+
+int Read_denyusers();
+int Check_ifuserdenied(char *);
+int Check_user(char *);
+void Checktimer();
+void Check_forchange();
+void Check_fordenychange();
+extern void Check_forallowchange();    /* For allowed users */
+extern int Check_ifuserallowed(char *);
+
+/*
+ * Reads Denyuserpath for all users to be excluded.
+ * Returns 0 if the user list was successfully loaded,
+ * and 1 in case of error.
+ * Logs any messages to the syslog daemon.
+ */
+
+int
+Read_denyusers()
+{
+    FILE *DFile;               /* Denied user file pointer */
+    off_t DPos = 0;            /* File counter */
+    char DChar;                        /* Character buffer */
+
+    /* Stat the file. If it does not exist, save the size as zero.
+     * Clear the denied user string. Return. */
+    if (stat(Denyuserpath, &FileBuf) == -1) {
+       if (errno == ENOENT) {
+           LastModTime = (time_t) 0;
+           DenyUserSize = 0;
+           free(DeniedUsers);
+           DeniedUsers = malloc(sizeof(char));
+           DeniedUsers[0] = '\0';
+           return 0;
+       } else {
+           syslog(LOG_USER | LOG_ERR, strerror(errno));
+           return 1;
+       }
+    }
+    /* If it exists, save the modification time and size */
+    LastModTime = FileBuf.st_mtime;
+    DenyUserSize = FileBuf.st_size;
+
+    /* Handle the special case of a zero length file */
+    if (DenyUserSize == 0) {
+       free(DeniedUsers);
+       DeniedUsers = malloc(sizeof(char));
+       DeniedUsers[0] = '\0';
+       return 0;
+    }
+    /* Free and allocate space for a string to store the denied usernames */
+    free(DeniedUsers);
+
+    if ((DeniedUsers = malloc(sizeof(char) * (DenyUserSize + 3))) == NULL) {
+       syslog(LOG_USER | LOG_ERR, "Read_denyusers: malloc(DeniedUsers) failed.");
+       return 1;
+    }
+    /* Open the denied user file. Report any errors. */
+
+    if ((DFile = fopen(Denyuserpath, "r")) == NULL) {
+       syslog(LOG_USER | LOG_ERR, "Read_denyusers: Failed to open denied user file.");
+       syslog(LOG_USER | LOG_ERR, strerror(errno));
+       return 1;
+    }
+    /* Read user names into the DeniedUsers string.
+     * Make sure each string is delimited by a space. */
+
+    DeniedUsers[DPos++] = ' ';
+
+    while (!feof(DFile)) {
+       if ((DChar = fgetc(DFile)) == EOF)
+           break;
+       else {
+           if (isspace(DChar))
+               DeniedUsers[DPos++] = ' ';
+           else
+               DeniedUsers[DPos++] = toupper(DChar);
+       }
+    }
+
+    DeniedUsers[DPos++] = ' ';
+    DeniedUsers[DPos] = '\0';
+    fclose(DFile);
+    return 0;
+}
+
+/*
+ * Check to see if the username provided by Squid appears in the denied
+ * user list. Returns 0 if the user was not found, and 1 if they were.
+ */
+
+int
+Check_ifuserdenied(char *ConnectingUser)
+{
+    static char CUBuf[NAMELEN + 1];
+    static int x;
+    static char DenyMsg[256];
+
+    /* If user string is empty, deny */
+    if (ConnectingUser[0] == '\0')
+       return 1;
+
+    /* If denied user list is empty, allow */
+    if (DenyUserSize == 0)
+       return 0;
+
+    /* Check if username string is found in the denied user list.
+     * If so, deny. If not, allow. Reconstruct the username
+     * to have whitespace, to avoid finding wrong string subsets. */
+
+    sscanf(ConnectingUser, " %s ", CUBuf);
+    sprintf(CUBuf, " %s ", CUBuf);
+
+    for (x = 0; x <= strlen(CUBuf); x++)
+       CUBuf[x] = toupper(CUBuf[x]);
+
+    if (strstr(DeniedUsers, CUBuf) == NULL)
+       return 0;
+    else {
+       sprintf(DenyMsg, "Denied access to user '%s'.", CUBuf);
+       syslog(LOG_USER | LOG_ERR, DenyMsg);
+       return 1;
+    }
+}
+
+/*
+ * Checks if there has been a change in the denied user file.
+ * If the modification time has changed, then reload the denied user list.
+ * This function is called by the SIGHUP signal handler.
+ */
+
+void
+Check_fordenychange()
+{
+    struct stat ChkBuf;                /* Stat data buffer */
+
+    /* Stat the denied user file. If it cannot be accessed, return. */
+
+    if (stat(Denyuserpath, &ChkBuf) == -1) {
+       if (errno == ENOENT) {
+           LastModTime = (time_t) 0;
+           DenyUserSize = 0;
+           free(DeniedUsers);
+           DeniedUsers = malloc(sizeof(char));
+           DeniedUsers[0] = '\0';
+           return;
+       } else {                /* Report error when accessing file */
+           syslog(LOG_USER | LOG_ERR, strerror(errno));
+           return;
+       }
+    }
+    /* If found, compare the modification time with the previously-recorded
+     * modification time.
+     * If the modification time has changed, reload the denied user list.
+     * Log a message of its actions. */
+
+    if (ChkBuf.st_mtime != LastModTime) {
+       syslog(LOG_USER | LOG_INFO, "Check_fordenychange: Reloading denied user list.");
+       Read_denyusers();
+    }
+}
+
+/*
+ * Decides if a user is denied or allowed.
+ * If they have been denied, or not allowed, return 1.
+ * Else return 0.
+ */
+
+int
+Check_user(char *ConnectingUser)
+{
+    if (Check_ifuserdenied(ConnectingUser) == 1)
+       return 1;
+
+    if (Check_ifuserallowed(ConnectingUser) == 0)
+       return 1;
+
+    return 0;
+}
+
+/*
+ * Checks the denied and allowed user files for change.
+ * This function is invoked when a SIGHUP signal is received.
+ * It is also run after every 60 seconds, at the next request.
+ */
+
+void
+Check_forchange()
+{
+    Check_fordenychange();
+    Check_forallowchange();
+}
+
+/*
+ * Checks the timer. If longer than 1 minute has passed since the last
+ * time someone has accessed the proxy, then check for changes in the
+ * denied user file. If longer than one minute hasn't passed, return.
+ */
+
+void
+Checktimer()
+{
+    static time_t Lasttime;    /* The last time the timer was checked */
+    static time_t Currenttime; /* The current time */
+
+    Currenttime = time(NULL);
+
+    /* If timeout has expired, check the denied user file, else return */
+    if (difftime(Currenttime, Lasttime) < 60)
+       return;
+    else {
+       Check_forchange();
+       Lasttime = Currenttime;
+    }
+}
diff --git a/helpers/basic_auth/MSNT/md4.c b/helpers/basic_auth/MSNT/md4.c
new file mode 100644 (file)
index 0000000..3943254
--- /dev/null
@@ -0,0 +1,209 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * a implementation of MD4 designed for use in the SMB authentication protocol
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTE: This code makes no attempt to be fast! 
+ * 
+ * It assumes that a int is at least 32 bits long
+ */
+
+typedef unsigned int uint32;
+
+static uint32 A, B, C, D;
+
+static uint32
+F(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | ((~X) & Z);
+}
+
+static uint32
+G(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | (X & Z) | (Y & Z);
+}
+
+static uint32
+H(uint32 X, uint32 Y, uint32 Z)
+{
+    return X ^ Y ^ Z;
+}
+
+static uint32
+lshift(uint32 x, int s)
+{
+    x &= 0xFFFFFFFF;
+    return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void
+mdfour64(uint32 * M)
+{
+    int j;
+    uint32 AA, BB, CC, DD;
+    uint32 X[16];
+
+    for (j = 0; j < 16; j++)
+       X[j] = M[j];
+
+    AA = A;
+    BB = B;
+    CC = C;
+    DD = D;
+
+    ROUND1(A, B, C, D, 0, 3);
+    ROUND1(D, A, B, C, 1, 7);
+    ROUND1(C, D, A, B, 2, 11);
+    ROUND1(B, C, D, A, 3, 19);
+    ROUND1(A, B, C, D, 4, 3);
+    ROUND1(D, A, B, C, 5, 7);
+    ROUND1(C, D, A, B, 6, 11);
+    ROUND1(B, C, D, A, 7, 19);
+    ROUND1(A, B, C, D, 8, 3);
+    ROUND1(D, A, B, C, 9, 7);
+    ROUND1(C, D, A, B, 10, 11);
+    ROUND1(B, C, D, A, 11, 19);
+    ROUND1(A, B, C, D, 12, 3);
+    ROUND1(D, A, B, C, 13, 7);
+    ROUND1(C, D, A, B, 14, 11);
+    ROUND1(B, C, D, A, 15, 19);
+
+    ROUND2(A, B, C, D, 0, 3);
+    ROUND2(D, A, B, C, 4, 5);
+    ROUND2(C, D, A, B, 8, 9);
+    ROUND2(B, C, D, A, 12, 13);
+    ROUND2(A, B, C, D, 1, 3);
+    ROUND2(D, A, B, C, 5, 5);
+    ROUND2(C, D, A, B, 9, 9);
+    ROUND2(B, C, D, A, 13, 13);
+    ROUND2(A, B, C, D, 2, 3);
+    ROUND2(D, A, B, C, 6, 5);
+    ROUND2(C, D, A, B, 10, 9);
+    ROUND2(B, C, D, A, 14, 13);
+    ROUND2(A, B, C, D, 3, 3);
+    ROUND2(D, A, B, C, 7, 5);
+    ROUND2(C, D, A, B, 11, 9);
+    ROUND2(B, C, D, A, 15, 13);
+
+    ROUND3(A, B, C, D, 0, 3);
+    ROUND3(D, A, B, C, 8, 9);
+    ROUND3(C, D, A, B, 4, 11);
+    ROUND3(B, C, D, A, 12, 15);
+    ROUND3(A, B, C, D, 2, 3);
+    ROUND3(D, A, B, C, 10, 9);
+    ROUND3(C, D, A, B, 6, 11);
+    ROUND3(B, C, D, A, 14, 15);
+    ROUND3(A, B, C, D, 1, 3);
+    ROUND3(D, A, B, C, 9, 9);
+    ROUND3(C, D, A, B, 5, 11);
+    ROUND3(B, C, D, A, 13, 15);
+    ROUND3(A, B, C, D, 3, 3);
+    ROUND3(D, A, B, C, 11, 9);
+    ROUND3(C, D, A, B, 7, 11);
+    ROUND3(B, C, D, A, 15, 15);
+
+    A += AA;
+    B += BB;
+    C += CC;
+    D += DD;
+
+    A &= 0xFFFFFFFF;
+    B &= 0xFFFFFFFF;
+    C &= 0xFFFFFFFF;
+    D &= 0xFFFFFFFF;
+
+    for (j = 0; j < 16; j++)
+       X[j] = 0;
+}
+
+static void
+copy64(uint32 * M, unsigned char *in)
+{
+    int i;
+
+    for (i = 0; i < 16; i++)
+       M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
+           (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
+}
+
+static void
+copy4(unsigned char *out, uint32 x)
+{
+    out[0] = x & 0xFF;
+    out[1] = (x >> 8) & 0xFF;
+    out[2] = (x >> 16) & 0xFF;
+    out[3] = (x >> 24) & 0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void
+mdfour(unsigned char *out, unsigned char *in, int n)
+{
+    unsigned char buf[128];
+    uint32 M[16];
+    uint32 b = n * 8;
+    int i;
+
+    A = 0x67452301;
+    B = 0xefcdab89;
+    C = 0x98badcfe;
+    D = 0x10325476;
+
+    while (n > 64) {
+       copy64(M, in);
+       mdfour64(M);
+       in += 64;
+       n -= 64;
+    }
+
+    for (i = 0; i < 128; i++)
+       buf[i] = 0;
+    memcpy(buf, in, n);
+    buf[n] = 0x80;
+
+    if (n <= 55) {
+       copy4(buf + 56, b);
+       copy64(M, buf);
+       mdfour64(M);
+    } else {
+       copy4(buf + 120, b);
+       copy64(M, buf);
+       mdfour64(M);
+       copy64(M, buf + 64);
+       mdfour64(M);
+    }
+
+    for (i = 0; i < 128; i++)
+       buf[i] = 0;
+    copy64(M, buf);
+
+    copy4(out, A);
+    copy4(out + 4, B);
+    copy4(out + 8, C);
+    copy4(out + 12, D);
+
+    A = B = C = D = 0;
+}
diff --git a/helpers/basic_auth/MSNT/msntauth-v2.0.lsm b/helpers/basic_auth/MSNT/msntauth-v2.0.lsm
new file mode 100644 (file)
index 0000000..0ad7d98
--- /dev/null
@@ -0,0 +1,13 @@
+Begin3
+Title:         msntauth 
+Version:       2.0 
+Entered-date:  10OCT00 
+Description:   Squid web proxy NT domain authentication module 
+Keywords:      Squid WWW proxy SMB NT domain authentication module source
+Author:         antonino.iannella@usa.net (Antonino Iannella)
+Maintained-by:  antonino.iannella@usa.net (Antonino Iannella)
+Primary-site:   sunsite.unc.edu /pub/Linux/system/network/misc
+               msntauth-v2.0.tgz
+Original-site:  http://stellarx.tripod.com
+Copying-policy: GPL
+End
diff --git a/helpers/basic_auth/MSNT/msntauth.c b/helpers/basic_auth/MSNT/msntauth.c
new file mode 100644 (file)
index 0000000..4f9da6a
--- /dev/null
@@ -0,0 +1,114 @@
+
+/*
+ * MSNT - Microsoft Windows NT domain squid authenticator module
+ * Version 1.2 by Stellar-X Pty Ltd, Antonino Iannella
+ * Fri Sep 22 00:56:05 CST 2000
+ * 
+ * Modified to act as a Squid authenticator module.
+ * Removed all Pike stuff.
+ * Returns OK for a successful authentication, or ERR upon error.
+ * 
+ * Uses code from -
+ * Andrew Tridgell 1997
+ * Richard Sharpe 1996
+ * Bill Welliver 1999
+ * Duane Wessels 2000
+ * 
+ * Released under GNU Public License
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <syslog.h>
+#include <sys/time.h>
+
+extern int OpenConfigFile();
+extern int QueryServers(char *, char *);
+extern void Checktimer();
+extern void Check_forchange();
+extern int Read_denyusers(void);
+extern int Read_allowusers(void);
+extern int Check_user(char *);
+
+/* Main program for simple authentication.
+ * Reads the denied user file. Sets alarm timer.
+ * Scans and checks for Squid input, and attempts to validate the user.
+ */
+
+int
+main()
+{
+    char username[256];
+    char password[256];
+    char wstr[256];
+
+    /* Read configuration file. Abort wildly if error. */
+    if (OpenConfigFile() == 1)
+       return 1;
+
+    /* Read denied and allowed user files.
+     * If they fails, there is a serious problem.
+     * Check syslog messages. Deny all users while in this state.
+     * The msntauth process should then be killed. */
+
+    if ((Read_denyusers() == 1) || (Read_allowusers() == 1)) {
+       while (1) {
+           fgets(wstr, 255, stdin);
+           puts("ERR");
+           fflush(stdout);
+       }
+    }
+    /* Make Check_forchange() the handle for HUP signals.
+     * Don't use alarms any more. I don't think it was very
+     * portable between systems. */
+    signal(SIGHUP, Check_forchange);
+
+    while (1) {
+       /* Read whole line from standard input. Terminate on break. */
+       if (fgets(wstr, 255, stdin) == NULL)
+           break;
+
+       /* Clear any current settings */
+       username[0] = '\0';
+       password[0] = '\0';
+       sscanf(wstr, "%s %s", username, password);      /* Extract parameters */
+
+       /* Check for invalid or blank entries */
+       if ((username[0] == '\0') || (password[0] == '\0')) {
+           puts("ERR");
+           fflush(stdout);
+           continue;
+       }
+       Checktimer();           /* Check if the user lists have changed */
+
+       /* Check if user is explicitly denied or allowed.
+        * If user passes both checks, they can be authenticated. */
+
+       if (Check_user(username) == 1)
+           puts("ERR");
+       else {
+           if (QueryServers(username, password) == 0)
+               puts("OK");
+           else
+               puts("ERR");
+       }
+
+       fflush(stdout);
+    }
+
+    return 0;
+}
diff --git a/helpers/basic_auth/MSNT/rfcnb-common.h b/helpers/basic_auth/MSNT/rfcnb-common.h
new file mode 100644 (file)
index 0000000..fab20c4
--- /dev/null
@@ -0,0 +1,40 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Common Structures etc Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _RFCNB_COMMON_H_
+#define _RFCNB_COMMON_H_
+
+/* A data structure we need */
+
+typedef struct RFCNB_Pkt {
+
+    char *data;                        /* The data in this portion */
+    int len;
+    struct RFCNB_Pkt *next;
+
+} RFCNB_Pkt;
+
+
+#endif /* _RFCNB_COMMON_H_ */
diff --git a/helpers/basic_auth/MSNT/rfcnb-error.h b/helpers/basic_auth/MSNT/rfcnb-error.h
new file mode 100644 (file)
index 0000000..6dd4682
--- /dev/null
@@ -0,0 +1,57 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Error Response Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _RFCNB_ERROR_H_
+#define _RFCNB_ERROR_H_
+
+/* Error responses */
+
+#define RFCNBE_Bad -1          /* Bad response */
+#define RFCNBE_OK 0
+
+/* these should follow the spec ... is there one ? */
+
+#define RFCNBE_NoSpace 1       /* Could not allocate space for a struct */
+#define RFCNBE_BadName 2       /* Could not translate a name            */
+#define RFCNBE_BadRead 3       /* Read sys call failed                  */
+#define RFCNBE_BadWrite 4      /* Write Sys call failed                 */
+#define RFCNBE_ProtErr 5       /* Protocol Error                        */
+#define RFCNBE_ConGone 6       /* Connection dropped                    */
+#define RFCNBE_BadHandle 7     /* Handle passed was bad                 */
+#define RFCNBE_BadSocket 8     /* Problems creating socket              */
+#define RFCNBE_ConnectFailed 9 /* Connect failed                        */
+#define RFCNBE_CallRejNLOCN 10 /* Call rejected, not listening on CN    */
+#define RFCNBE_CallRejNLFCN 11 /* Call rejected, not listening for CN   */
+#define RFCNBE_CallRejCNNP  12 /* Call rejected, called name not present */
+#define RFCNBE_CallRejInfRes 13        /* Call rejetced, name ok, no resources   */
+#define RFCNBE_CallRejUnSpec 14        /* Call rejected, unspecified error      */
+#define RFCNBE_BadParam      15        /* Bad parameters passed ...             */
+#define RFCNBE_Timeout       16        /* IO Timed out                          */
+
+/* Text strings for the error responses                                 */
+
+extern char *RFCNB_Error_Strings[];
+
+#endif /* _RFCNB_ERROR_H_ */
diff --git a/helpers/basic_auth/MSNT/rfcnb-io.c b/helpers/basic_auth/MSNT/rfcnb-io.c
new file mode 100644 (file)
index 0000000..a60de07
--- /dev/null
@@ -0,0 +1,415 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* #include <features.h> */
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <sys/uio.h>
+#include <sys/signal.h>
+
+int RFCNB_Timeout = 0;         /* Timeout in seconds ... */
+
+void
+rfcnb_alarm(int sig)
+{
+
+    fprintf(stderr, "IO Timed out ...\n");
+
+}
+
+/* Set timeout value and setup signal handling */
+
+int
+RFCNB_Set_Timeout(int seconds)
+{
+#ifdef __GLIBC__
+    int temp;
+#endif
+    /* If we are on a Bezerkeley system, use sigvec, else sigaction */
+#ifndef SA_RESTART
+    struct sigvec invec, outvec;
+#else
+    struct sigaction inact, outact;
+#endif
+
+    RFCNB_Timeout = seconds;
+
+    if (RFCNB_Timeout > 0) {   /* Set up handler to ignore but not restart */
+
+#ifndef SA_RESTART
+       invec.sv_handler = (void (*)()) rfcnb_alarm;
+       invec.sv_mask = 0;
+       invec.sv_flags = SV_INTERRUPT;
+
+       if (sigvec(SIGALRM, &invec, &outvec) < 0)
+           return (-1);
+#else
+       inact.sa_handler = (void (*)()) rfcnb_alarm;
+#ifdef SOLARIS
+       /* Solaris seems to have an array of vectors ... */
+       inact.sa_mask.__sigbits[0] = 0;
+       inact.sa_mask.__sigbits[1] = 0;
+       inact.sa_mask.__sigbits[2] = 0;
+       inact.sa_mask.__sigbits[3] = 0;
+#else
+#ifdef __GLIBC__
+       for (temp = 0; temp < 32; temp++)
+           inact.sa_mask.__val[temp] = 0;
+#else
+       inact.sa_mask = 0;
+#endif
+#endif
+       inact.sa_flags = 0;     /* Don't restart */
+
+       if (sigaction(SIGALRM, &inact, &outact) < 0)
+           return (-1);
+
+#endif
+
+    }
+    return (0);
+
+}
+
+/* Discard the rest of an incoming packet as we do not have space for it
+ * in the buffer we allocated or were passed ...                         */
+
+int
+RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
+{
+    char temp[100];            /* Read into here */
+    int rest, this_read, bytes_read;
+
+    /* len is the amount we should read */
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
+#endif
+
+    rest = len;
+
+    while (rest > 0) {
+
+       this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
+
+       bytes_read = read(con->fd, temp, this_read);
+
+       if (bytes_read <= 0) {  /* Error so return */
+
+           if (bytes_read < 0)
+               RFCNB_errno = RFCNBE_BadRead;
+           else
+               RFCNB_errno = RFCNBE_ConGone;
+
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       rest = rest - bytes_read;
+
+    }
+
+    return (0);
+
+}
+
+
+/* Send an RFCNB packet to the connection.
+ * 
+ * We just send each of the blocks linked together ... 
+ * 
+ * If we can, try to send it as one iovec ... 
+ * 
+ */
+
+int
+RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int len_sent, tot_sent, this_len;
+    struct RFCNB_Pkt *pkt_ptr;
+    char *this_data;
+    int i;
+    struct iovec io_list[10];  /* We should never have more      */
+    /* If we do, this will blow up ... */
+
+    /* Try to send the data ... We only send as many bytes as len claims */
+    /* We should try to stuff it into an IOVEC and send as one write     */
+
+
+    pkt_ptr = pkt;
+    len_sent = tot_sent = 0;   /* Nothing sent so far */
+    i = 0;
+
+    while ((pkt_ptr != NULL) & (i < 10)) {     /* Watch that magic number! */
+
+       this_len = pkt_ptr->len;
+       this_data = pkt_ptr->data;
+       if ((tot_sent + this_len) > len)
+           this_len = len - tot_sent;  /* Adjust so we don't send too much */
+
+       /* Now plug into the iovec ... */
+
+       io_list[i].iov_len = this_len;
+       io_list[i].iov_base = this_data;
+       i++;
+
+       tot_sent += this_len;
+
+       if (tot_sent == len)
+           break;              /* Let's not send too much */
+
+       pkt_ptr = pkt_ptr->next;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
+#endif
+
+    /* Set up an alarm if timeouts are set ... */
+
+    if (RFCNB_Timeout > 0)
+       alarm(RFCNB_Timeout);
+
+    if ((len_sent = writev(con->fd, io_list, i)) < 0) {                /* An error */
+
+       con->rfc_errno = errno;
+       if (errno == EINTR)     /* We were interrupted ... */
+           RFCNB_errno = RFCNBE_Timeout;
+       else
+           RFCNB_errno = RFCNBE_BadWrite;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    if (len_sent < tot_sent) { /* Less than we wanted */
+       if (errno == EINTR)     /* We were interrupted */
+           RFCNB_errno = RFCNBE_Timeout;
+       else
+           RFCNB_errno = RFCNBE_BadWrite;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    if (RFCNB_Timeout > 0)
+       alarm(0);               /* Reset that sucker */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Len sent = %i ...\n", len_sent);
+    RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent);    /* Print what send ... */
+
+#endif
+
+    return (len_sent);
+
+}
+
+/* Read an RFCNB packet off the connection. 
+ * 
+ * We read the first 4 bytes, that tells us the length, then read the
+ * rest. We should implement a timeout, but we don't just yet 
+ * 
+ */
+
+
+int
+RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int read_len, pkt_len;
+    char hdr[RFCNB_Pkt_Hdr_Len];       /* Local space for the header */
+    struct RFCNB_Pkt *pkt_frag;
+    int more, this_time, offset, frag_len, this_len;
+    BOOL seen_keep_alive = TRUE;
+
+    /* Read that header straight into the buffer */
+
+    if (len < RFCNB_Pkt_Hdr_Len) {     /* What a bozo */
+
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Trying to read less than a packet:");
+       perror("");
+#endif
+       RFCNB_errno = RFCNBE_BadParam;
+       return (RFCNBE_Bad);
+
+    }
+    /* We discard keep alives here ... */
+
+    if (RFCNB_Timeout > 0)
+       alarm(RFCNB_Timeout);
+
+    while (seen_keep_alive) {
+
+       if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) {         /* Problems */
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "Reading the packet, we got:");
+           perror("");
+#endif
+           if (errno == EINTR)
+               RFCNB_errno = RFCNBE_Timeout;
+           else
+               RFCNB_errno = RFCNBE_BadRead;
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       /* Now we check out what we got */
+
+       if (read_len == 0) {    /* Connection closed, send back eof?  */
+
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "Connection closed reading\n");
+#endif
+
+           if (errno == EINTR)
+               RFCNB_errno = RFCNBE_Timeout;
+           else
+               RFCNB_errno = RFCNBE_ConGone;
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
+
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "RFCNB KEEP ALIVE received\n");
+#endif
+
+       } else {
+           seen_keep_alive = FALSE;
+       }
+
+    }
+
+    /* What if we got less than or equal to a hdr size in bytes? */
+
+    if (read_len < sizeof(hdr)) {      /* We got a small packet */
+
+       /* Now we need to copy the hdr portion we got into the supplied packet */
+
+       memcpy(pkt->data, hdr, read_len);       /*Copy data */
+
+#ifdef RFCNB_DEBUG
+       RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
+#endif
+
+       return (read_len);
+
+    }
+    /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
+
+    pkt_len = RFCNB_Pkt_Len(hdr);
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
+#endif
+
+    /* Now copy in the hdr */
+
+    memcpy(pkt->data, hdr, sizeof(hdr));
+
+    /* Get the rest of the packet ... first figure out how big our buf is? */
+    /* And make sure that we handle the fragments properly ... Sure should */
+    /* use an iovec ...                                                    */
+
+    if (len < pkt_len)         /* Only get as much as we have space for */
+       more = len - RFCNB_Pkt_Hdr_Len;
+    else
+       more = pkt_len;
+
+    this_time = 0;
+
+    /* We read for each fragment ... */
+
+    if (pkt->len == read_len) {        /* If this frag was exact size */
+       pkt_frag = pkt->next;   /* Stick next lot in next frag */
+       offset = 0;             /* then we start at 0 in next  */
+    } else {
+       pkt_frag = pkt;         /* Otherwise use rest of this frag */
+       offset = RFCNB_Pkt_Hdr_Len;     /* Otherwise skip the header       */
+    }
+
+    frag_len = pkt_frag->len;
+
+    if (more <= frag_len)      /* If len left to get less than frag space */
+       this_len = more;        /* Get the rest ...                        */
+    else
+       this_len = frag_len - offset;
+
+    while (more > 0) {
+
+       if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) {    /* Problems */
+
+           if (errno == EINTR) {
+
+               RFCNB_errno = RFCNB_Timeout;
+
+           } else {
+               if (this_time < 0)
+                   RFCNB_errno = RFCNBE_BadRead;
+               else
+                   RFCNB_errno = RFCNBE_ConGone;
+           }
+
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
+           this_time, this_len, more);
+#endif
+
+       read_len = read_len + this_time;        /* How much have we read ... */
+
+       /* Now set up the next part */
+
+       if (pkt_frag->next == NULL)
+           break;              /* That's it here */
+
+       pkt_frag = pkt_frag->next;
+       this_len = pkt_frag->len;
+       offset = 0;
+
+       more = more - this_time;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
+    RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
+#endif
+
+    if (read_len < (pkt_len + sizeof(hdr))) {  /* Discard the rest */
+
+       return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
+
+    }
+    if (RFCNB_Timeout > 0)
+       alarm(0);               /* Reset that sucker */
+
+    return (read_len + sizeof(RFCNB_Hdr));
+}
diff --git a/helpers/basic_auth/MSNT/rfcnb-io.h b/helpers/basic_auth/MSNT/rfcnb-io.h
new file mode 100644 (file)
index 0000000..267d12f
--- /dev/null
@@ -0,0 +1,28 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
diff --git a/helpers/basic_auth/MSNT/rfcnb-priv.h b/helpers/basic_auth/MSNT/rfcnb-priv.h
new file mode 100644 (file)
index 0000000..1e906b3
--- /dev/null
@@ -0,0 +1,150 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Defines we need */
+
+
+#define GLOBAL extern
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "byteorder.h"
+
+#ifdef RFCNB_PORT
+#define RFCNB_Default_Port RFCNB_PORT
+#else
+#define RFCNB_Default_Port 139
+#endif
+
+#define RFCNB_MAX_STATS 1
+
+/* Protocol defines we need */
+
+#define RFCNB_SESSION_MESSAGE 0
+#define RFCNB_SESSION_REQUEST 0x81
+#define RFCNB_SESSION_ACK 0x82
+#define RFCNB_SESSION_REJ 0x83
+#define RFCNB_SESSION_RETARGET 0x84
+#define RFCNB_SESSION_KEEP_ALIVE 0x85
+
+/* Structures      */
+
+typedef struct redirect_addr *redirect_ptr;
+
+struct redirect_addr {
+
+    struct in_addr ip_addr;
+    int port;
+    redirect_ptr next;
+
+};
+
+typedef struct RFCNB_Con {
+
+    int fd;                    /* File descripter for TCP/IP connection */
+    int rfc_errno;             /* last error                            */
+    int timeout;               /* How many milli-secs before IO times out */
+    int redirects;             /* How many times we were redirected     */
+    struct redirect_addr *redirect_list;       /* First is first address */
+    struct redirect_addr *last_addr;
+
+} RFCNB_Con;
+
+typedef char RFCNB_Hdr[4];     /* The header is 4 bytes long with  */
+                                   /* char[0] as the type, char[1] the */
+                                   /* flags, and char[2..3] the length */
+
+/* Macros to extract things from the header. These are for portability
+ * between architecture types where we are worried about byte order     */
+
+#define RFCNB_Pkt_Hdr_Len        4
+#define RFCNB_Pkt_Sess_Len       72
+#define RFCNB_Pkt_Retarg_Len     10
+#define RFCNB_Pkt_Nack_Len       5
+#define RFCNB_Pkt_Type_Offset    0
+#define RFCNB_Pkt_Flags_Offset   1
+#define RFCNB_Pkt_Len_Offset     2     /* Length is 2 bytes plus a flag bit */
+#define RFCNB_Pkt_N1Len_Offset   4
+#define RFCNB_Pkt_Called_Offset  5
+#define RFCNB_Pkt_N2Len_Offset   38
+#define RFCNB_Pkt_Calling_Offset 39
+#define RFCNB_Pkt_Error_Offset   4
+#define RFCNB_Pkt_IP_Offset      4
+#define RFCNB_Pkt_Port_Offset    8
+
+/* The next macro isolates the length of a packet, including the bit in the
+ * flags                                                                   */
+
+#define RFCNB_Pkt_Len(p)  (PVAL(p, 3) | (PVAL(p, 2) << 8) |     \
+                          ((PVAL(p, RFCNB_Pkt_Flags_Offset) & 0x01) << 16))
+
+#define RFCNB_Put_Pkt_Len(p, v) (p[1] = ((v >> 16) & 1)); \
+                               (p[2] = ((v >> 8) & 0xFF)); \
+                               (p[3] = (v & 0xFF));
+
+#define RFCNB_Pkt_Type(p) (CVAL(p, RFCNB_Pkt_Type_Offset))
+
+/*typedef struct RFCNB_Hdr {
+ * 
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 len;
+ * 
+ * } RFCNB_Hdr;
+ * 
+ * typedef struct RFCNB_Sess_Pkt {
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 length;
+ * unsigned char n1_len;
+ * char called_name[33];
+ * unsigned char n2_len;
+ * char calling_name[33];
+ * } RFCNB_Sess_Pkt;
+ * 
+ * 
+ * typedef struct RFCNB_Nack_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * unsigned char error;
+ * 
+ * } RFCNB_Nack_Pkt;
+ * 
+ * typedef struct RFCNB_Retarget_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * int dest_ip;
+ * unsigned char port;
+ * 
+ * } RFCNB_Redir_Pkt; */
+
+/* Static variables */
+
+/* Only declare this if not defined */
+
+#ifndef RFCNB_ERRNO
+extern int RFCNB_errno;
+extern int RFCNB_saved_errno;  /* Save this from point of error */
+#endif
diff --git a/helpers/basic_auth/MSNT/rfcnb-util.c b/helpers/basic_auth/MSNT/rfcnb-util.c
new file mode 100644 (file)
index 0000000..55928df
--- /dev/null
@@ -0,0 +1,555 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+char *RFCNB_Error_Strings[] =
+{
+
+    "RFCNBE_OK: Routine completed successfully.",
+    "RFCNBE_NoSpace: No space available for a malloc call.",
+    "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+    "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+    "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+    "RFCNBE_ProtErr: A protocol error has occurred.",
+    "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+    "RFCNBE_BadHandle: Bad connection handle passed.",
+    "RFCNBE_BadSocket: Problems creating socket.",
+    "RFCNBE_ConnectFailed: Connection failed. See errno.",
+    "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+    "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+    "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+    "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+    "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+    "RFCNBE_BadParam: Bad parameters passed to a routine.",
+    "RFCNBE_Timeout: IO Operation timed out ..."
+
+};
+
+extern void (*Prot_Print_Routine) ();  /* Pointer to protocol print routine */
+
+/* Convert name and pad to 16 chars as needed */
+/* Name 1 is a C string with null termination, name 2 may not be */
+/* If SysName is true, then put a <00> on end, else space>       */
+
+void
+RFCNB_CvtPad_Name(char *name1, char *name2)
+{
+    char c, c1, c2;
+    int i, len;
+
+    len = strlen(name1);
+
+    for (i = 0; i < 16; i++) {
+
+       if (i >= len) {
+
+           c1 = 'C';
+           c2 = 'A';           /* CA is a space */
+
+       } else {
+
+           c = name1[i];
+           c1 = (char) ((int) c / 16 + (int) 'A');
+           c2 = (char) ((int) c % 16 + (int) 'A');
+       }
+
+       name2[i * 2] = c1;
+       name2[i * 2 + 1] = c2;
+
+    }
+
+    name2[32] = 0;             /* Put in the nll ... */
+
+}
+
+/* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
+ * Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
+ * to produce the next byte in the name.
+ * 
+ * This routine assumes that AName is 16 bytes long and that NBName has 
+ * space for 32 chars, so be careful ... 
+ * 
+ */
+
+void
+RFCNB_AName_To_NBName(char *AName, char *NBName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+       c = AName[i];
+
+       c1 = (char) ((c >> 4) + 'A');
+       c2 = (char) ((c & 0xF) + 'A');
+
+       NBName[i * 2] = c1;
+       NBName[i * 2 + 1] = c2;
+    }
+
+    NBName[32] = 0;            /* Put in a null */
+
+}
+
+/* Do the reverse of the above ... */
+
+void
+RFCNB_NBName_To_AName(char *NBName, char *AName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+       c1 = NBName[i * 2];
+       c2 = NBName[i * 2 + 1];
+
+       c = (char) (((int) c1 - (int) 'A') * 16 + ((int) c2 - (int) 'A'));
+
+       AName[i] = c;
+
+    }
+
+    AName[i] = 0;              /* Put a null on the end ... */
+
+}
+
+/* Print a string of bytes in HEX etc */
+
+void
+RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
+{
+    char c1, c2, outbuf1[33];
+    unsigned char c;
+    int i, j;
+    struct RFCNB_Pkt *pkt_ptr = pkt;
+    static char Hex_List[17] = "0123456789ABCDEF";
+
+    j = 0;
+
+    /* We only want to print as much as sepcified in Len */
+
+    while (pkt_ptr != NULL) {
+
+       for (i = 0;
+           i < ((Len > (pkt_ptr->len) ? pkt_ptr->len : Len) - Offset);
+           i++) {
+
+           c = pkt_ptr->data[i + Offset];
+           c1 = Hex_List[c >> 4];
+           c2 = Hex_List[c & 0xF];
+
+           outbuf1[j++] = c1;
+           outbuf1[j++] = c2;
+
+           if (j == 32) {      /* Print and reset */
+               outbuf1[j] = 0;
+               fprintf(fd, "    %s\n", outbuf1);
+               j = 0;
+           }
+       }
+
+       Offset = 0;
+       Len = Len - pkt_ptr->len;       /* Reduce amount by this much */
+       pkt_ptr = pkt_ptr->next;
+
+    }
+
+    /* Print last lot in the buffer ... */
+
+    if (j > 0) {
+
+       outbuf1[j] = 0;
+       fprintf(fd, "    %s\n", outbuf1);
+
+    }
+    fprintf(fd, "\n");
+
+}
+
+/* Get a packet of size n */
+
+struct RFCNB_Pkt *
+RFCNB_Alloc_Pkt(int n)
+{
+    RFCNB_Pkt *pkt;
+
+    if ((pkt = (struct RFCNB_Pkt *) malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (NULL);
+
+    }
+    pkt->next = NULL;
+    pkt->len = n;
+
+    if (n == 0)
+       return (pkt);
+
+    if ((pkt->data = (char *) malloc(n)) == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       free(pkt);
+       return (NULL);
+
+    }
+    return (pkt);
+
+}
+
+/* Free up a packet */
+
+void
+RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
+{
+    struct RFCNB_Pkt *pkt_next;
+    char *data_ptr;
+
+    while (pkt != NULL) {
+
+       pkt_next = pkt->next;
+
+       data_ptr = pkt->data;
+
+       if (data_ptr != NULL)
+           free(data_ptr);
+
+       free(pkt);
+
+       pkt = pkt_next;
+
+    }
+
+}
+
+/* Print an RFCNB packet */
+
+void
+RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
+{
+    char lname[17];
+
+    /* We assume that the first fragment is the RFCNB Header  */
+    /* We should loop through the fragments printing them out */
+
+    fprintf(fd, "RFCNB Pkt %s:", dirn);
+
+    switch (RFCNB_Pkt_Type(pkt->data)) {
+
+    case RFCNB_SESSION_MESSAGE:
+
+       fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt->data));
+       RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
+#ifdef RFCNB_PRINT_DATA
+           RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+#else
+           40);
+#endif
+
+       if (Prot_Print_Routine != 0) {  /* Print the rest of the packet */
+
+           Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
+               RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+
+       }
+       break;
+
+    case RFCNB_SESSION_REQUEST:
+
+       fprintf(fd, "SESSION REQUEST: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+       RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Called_Offset), lname);
+       fprintf(fd, "  Called Name: %s\n", lname);
+       RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Calling_Offset), lname);
+       fprintf(fd, "  Calling Name: %s\n", lname);
+
+       break;
+
+    case RFCNB_SESSION_ACK:
+
+       fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       break;
+
+    case RFCNB_SESSION_REJ:
+       fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       if (RFCNB_Pkt_Len(pkt->data) < 1) {
+           fprintf(fd, "   Protocol Error, short Reject packet!\n");
+       } else {
+           fprintf(fd, "   Error = %x\n", CVAL(pkt->data, RFCNB_Pkt_Error_Offset));
+       }
+
+       break;
+
+    case RFCNB_SESSION_RETARGET:
+
+       fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       /* Print out the IP address etc and the port? */
+
+       break;
+
+    case RFCNB_SESSION_KEEP_ALIVE:
+
+       fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+       break;
+
+    default:
+
+       break;
+    }
+
+}
+
+/* Resolve a name into an address */
+
+int
+RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
+{
+    int addr;                  /* Assumes IP4, 32 bit network addresses */
+    struct hostent *hp;
+
+    /* Use inet_addr to try to convert the address */
+
+    if ((addr = inet_addr(host)) == INADDR_NONE) {     /* Oh well, a good try :-) */
+
+       /* Now try a name look up with gethostbyname */
+
+       if ((hp = gethostbyname(host)) == NULL) {       /* Not in DNS */
+
+           /* Try NetBIOS name lookup, how the hell do we do that? */
+
+           RFCNB_errno = RFCNBE_BadName;       /* Is this right? */
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       } else {                /* We got a name */
+
+           memcpy((void *) Dest_IP, (void *) hp->h_addr_list[0], sizeof(struct in_addr));
+
+       }
+    } else {                   /* It was an IP address */
+
+       memcpy((void *) Dest_IP, (void *) &addr, sizeof(struct in_addr));
+
+    }
+
+    return 0;
+
+}
+
+/* Disconnect the TCP connection to the server */
+
+int
+RFCNB_Close(int socket)
+{
+
+    close(socket);
+
+    /* If we want to do error recovery, here is where we put it */
+
+    return 0;
+
+}
+
+/* Connect to the server specified in the IP address.
+ * Not sure how to handle socket options etc.         */
+
+int
+RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
+{
+    struct sockaddr_in Socket;
+    int fd;
+
+    /* Create a socket */
+
+    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {  /* Handle the error */
+
+       RFCNB_errno = RFCNBE_BadSocket;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    bzero((char *) &Socket, sizeof(Socket));
+    memcpy((char *) &Socket.sin_addr, (char *) &Dest_IP, sizeof(Dest_IP));
+
+    Socket.sin_port = htons(port);
+    Socket.sin_family = PF_INET;
+
+    /* Now connect to the destination */
+
+    if (connect(fd, (struct sockaddr *) &Socket, sizeof(Socket)) < 0) {                /* Error */
+
+       close(fd);
+       RFCNB_errno = RFCNBE_ConnectFailed;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    return (fd);
+
+}
+
+/* handle the details of establishing the RFCNB session with remote 
+ * end 
+ * 
+ */
+
+int
+RFCNB_Session_Req(struct RFCNB_Con *con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port)
+{
+    char *sess_pkt;
+
+    /* Response packet should be no more than 9 bytes, make 16 jic */
+
+    char resp[16];
+    int len;
+    struct RFCNB_Pkt *pkt, res_pkt;
+
+    /* We build and send the session request, then read the response */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
+
+    if (pkt == NULL) {
+
+       return (RFCNBE_Bad);    /* Leave the error that RFCNB_Alloc_Pkt gives) */
+
+    }
+    sess_pkt = pkt->data;      /* Get pointer to packet proper */
+
+    sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
+    RFCNB_Put_Pkt_Len(sess_pkt, (RFCNB_Pkt_Sess_Len - RFCNB_Pkt_Hdr_Len));
+    sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
+    sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
+
+    RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
+    RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
+
+    /* Now send the packet */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
+
+       return (RFCNBE_Bad);    /* Should be able to write that lot ... */
+
+    }
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Getting packet.\n");
+
+#endif
+
+    res_pkt.data = resp;
+    res_pkt.len = sizeof(resp);
+    res_pkt.next = NULL;
+
+    if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
+
+       return (RFCNBE_Bad);
+
+    }
+    /* Now analyze the packet ... */
+
+    switch (RFCNB_Pkt_Type(resp)) {
+
+    case RFCNB_SESSION_REJ:    /* Didnt like us ... too bad */
+
+       /* Why did we get rejected ? */
+
+       switch (CVAL(resp, RFCNB_Pkt_Error_Offset)) {
+
+       case 0x80:
+           RFCNB_errno = RFCNBE_CallRejNLOCN;
+           break;
+       case 0x81:
+           RFCNB_errno = RFCNBE_CallRejNLFCN;
+           break;
+       case 0x82:
+           RFCNB_errno = RFCNBE_CallRejCNNP;
+           break;
+       case 0x83:
+           RFCNB_errno = RFCNBE_CallRejInfRes;
+           break;
+       case 0x8F:
+           RFCNB_errno = RFCNBE_CallRejUnSpec;
+           break;
+       default:
+           RFCNB_errno = RFCNBE_ProtErr;
+           break;
+       }
+
+       return (RFCNBE_Bad);
+       break;
+
+    case RFCNB_SESSION_ACK:    /* Got what we wanted ...      */
+
+       return (0);
+       break;
+
+    case RFCNB_SESSION_RETARGET:       /* Go elsewhere                */
+
+       *redirect = TRUE;       /* Copy port and ip addr       */
+
+       memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
+       *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
+
+       return (0);
+       break;
+
+    default:                   /* A protocol error */
+
+       RFCNB_errno = RFCNBE_ProtErr;
+       return (RFCNBE_Bad);
+       break;
+    }
+}
diff --git a/helpers/basic_auth/MSNT/rfcnb-util.h b/helpers/basic_auth/MSNT/rfcnb-util.h
new file mode 100644 (file)
index 0000000..e19330d
--- /dev/null
@@ -0,0 +1,51 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+void RFCNB_CvtPad_Name(char *name1, char *name2);
+
+void RFCNB_AName_To_NBName(char *AName, char *NBName);
+
+void RFCNB_NBName_To_AName(char *NBName, char *AName);
+
+void RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP);
+
+int RFCNB_Close(int socket);
+
+int RFCNB_IP_Connect(struct in_addr Dest_IP, int port);
+
+int RFCNB_Session_Req(RFCNB_Con * con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
diff --git a/helpers/basic_auth/MSNT/rfcnb.h b/helpers/basic_auth/MSNT/rfcnb.h
new file mode 100644 (file)
index 0000000..d1ebde4
--- /dev/null
@@ -0,0 +1,48 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Error responses */
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+
+/* Defines we need */
+
+#define RFCNB_Default_Port 139
+
+/* Definition of routines we define */
+
+void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port);
+
+int RFCNB_Send(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Recv(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Hangup(void *con_Handle);
+
+void *RFCNB_Listen();
+
+void RFCNB_Get_Error(char *buffer, int buf_len);
diff --git a/helpers/basic_auth/MSNT/session.c b/helpers/basic_auth/MSNT/session.c
new file mode 100644 (file)
index 0000000..76eb81a
--- /dev/null
@@ -0,0 +1,363 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * Session Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int RFCNB_errno = 0;
+int RFCNB_saved_errno = 0;
+#define RFCNB_ERRNO
+
+#include "std-includes.h"
+#include <netinet/tcp.h>
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+int RFCNB_Stats[RFCNB_MAX_STATS];
+
+void (*Prot_Print_Routine) () = NULL;  /* Pointer to print routine */
+
+/* Set up a session with a remote name. We are passed Called_Name as a
+ * string which we convert to a NetBIOS name, ie space terminated, up to
+ * 16 characters only if we need to. If Called_Address is not empty, then
+ * we use it to connect to the remote end, but put in Called_Name ... Called 
+ * Address can be a DNS based name, or a TCP/IP address ...
+ */
+
+void *
+RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port)
+{
+    struct RFCNB_Con *con;
+    struct in_addr Dest_IP;
+    int Client;
+    BOOL redirect;
+    struct redirect_addr *redir_addr;
+    char *Service_Address;
+
+    /* Now, we really should look up the port in /etc/services ... */
+
+    if (port == 0)
+       port = RFCNB_Default_Port;
+
+    /* Create a connection structure first */
+
+    if ((con = (struct RFCNB_Con *) malloc(sizeof(struct RFCNB_Con))) == NULL) {       /* Error in size */
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (NULL);
+
+    }
+    con->fd = -0;              /* no descriptor yet */
+    con->rfc_errno = 0;                /* no error yet */
+    con->timeout = 0;          /* no timeout   */
+    con->redirects = 0;
+    con->redirect_list = NULL; /* Fix bug still in version 0.50 */
+
+    /* Resolve that name into an IP address */
+
+    Service_Address = Called_Name;
+    if (strcmp(Called_Address, "") != 0) {     /* If the Called Address = "" */
+       Service_Address = Called_Address;
+    }
+    if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) {   /* Error */
+
+       /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
+
+       return (NULL);
+
+    }
+    /* Now connect to the remote end */
+
+    redirect = TRUE;           /* Fudge this one so we go once through */
+
+    while (redirect) {         /* Connect and get session info etc */
+
+       redirect = FALSE;       /* Assume all OK */
+
+       /* Build the redirect info. First one is first addr called */
+       /* And tack it onto the list of addresses we called        */
+
+       if ((redir_addr = (struct redirect_addr *) malloc(sizeof(struct redirect_addr))) == NULL) {     /* Could not get space */
+
+           RFCNB_errno = RFCNBE_NoSpace;
+           RFCNB_saved_errno = errno;
+           return (NULL);
+
+       }
+       memcpy((char *) &(redir_addr->ip_addr), (char *) &Dest_IP, sizeof(Dest_IP));
+       redir_addr->port = port;
+       redir_addr->next = NULL;
+
+       if (con->redirect_list == NULL) {       /* Stick on head */
+
+           con->redirect_list = con->last_addr = redir_addr;
+
+       } else {
+
+           con->last_addr->next = redir_addr;
+           con->last_addr = redir_addr;
+
+       }
+
+       /* Now, make that connection */
+
+       if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) {   /* Error */
+
+           /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
+
+           return (NULL);
+
+       }
+       con->fd = Client;
+
+       /* Now send and handle the RFCNB session request              */
+       /* If we get a redirect, we will comeback with redirect true 
+        * and a new IP address in DEST_IP                            */
+
+       if ((errno = RFCNB_Session_Req(con,
+                   Called_Name,
+                   Calling_Name,
+                   &redirect, &Dest_IP, &port)) < 0) {
+
+           /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
+
+           return (NULL);
+
+       }
+       if (redirect) {
+
+           /* We have to close the connection, and then try again */
+
+           (con->redirects)++;
+
+           RFCNB_Close(con->fd);       /* Close it */
+
+       }
+    }
+
+    return (con);
+
+}
+
+/* We send a packet to the other end ... for the moment, we treat the 
+ * data as a series of pointers to blocks of data ... we should check the
+ * length ... */
+
+int
+RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    char *hdr;
+    int len;
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    pkt->next = udata;         /* The user data we want to send */
+
+    hdr = pkt->data;
+
+    /* Following crap is for portability across multiple UNIX machines */
+
+    *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
+    RFCNB_Put_Pkt_Len(hdr, Length);
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+       /* No need to change RFCNB_errno as it was done by put_pkt ...     */
+
+       return (RFCNBE_Bad);    /* Should be able to write that lot ... */
+
+    }
+    /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (len);
+
+}
+
+/* We pick up a message from the internet ... We have to worry about 
+ * non-message packets ...                                           */
+
+int
+RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    int ret_len;
+
+    if (con_Handle == NULL) {
+
+       RFCNB_errno = RFCNBE_BadHandle;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    /* Now get a packet from below. We allocate a header first */
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    pkt->next = Data;          /* Plug in the data portion */
+
+    if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
+#endif
+
+       return (RFCNBE_Bad);
+
+    }
+    /* We should check that we go a message and not a keep alive */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (ret_len);
+
+}
+
+/* We just disconnect from the other end, as there is nothing in the RFCNB */
+/* protocol that specifies any exchange as far as I can see                */
+
+int
+RFCNB_Hangup(struct RFCNB_Con *con_Handle)
+{
+
+    if (con_Handle != NULL) {
+       RFCNB_Close(con_Handle->fd);    /* Could this fail? */
+       free(con_Handle);
+    }
+    return 0;
+
+
+}
+
+/* Set TCP_NODELAY on the socket                                          */
+
+int
+RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
+{
+
+    return (setsockopt(con_Handle->fd, IPPROTO_TCP, TCP_NODELAY,
+           (char *) &yn, sizeof(yn)));
+
+}
+
+
+/* Listen for a connection on a port???, when                             */
+/* the connection comes in, we return with the connection                 */
+
+void
+RFCNB_Listen()
+{
+
+}
+
+/* Pick up the last error response as a string, hmmm, this routine should */
+/* have been different ...                                                */
+
+void
+RFCNB_Get_Error(char *buffer, int buf_len)
+{
+
+    if (RFCNB_saved_errno <= 0) {
+       sprintf(buffer, "%s", RFCNB_Error_Strings[RFCNB_errno]);
+    } else {
+       sprintf(buffer, "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
+           strerror(RFCNB_saved_errno));
+    }
+
+}
+
+/* Pick up the last error response and returns as a code                 */
+
+int
+RFCNB_Get_Last_Error()
+{
+
+    return (RFCNB_errno);
+
+}
+
+/* Pick up saved errno as well */
+
+int
+RFCNB_Get_Last_Errno()
+{
+
+    return (RFCNB_saved_errno);
+
+}
+
+/* Pick up the last error response and return in string ...             */
+
+void
+RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
+{
+
+    strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len);
+
+}
+
+/* Register a higher level protocol print routine */
+
+void
+RFCNB_Register_Print_Routine(void (*fn) ())
+{
+
+    Prot_Print_Routine = fn;
+
+}
diff --git a/helpers/basic_auth/MSNT/smbdes.c b/helpers/basic_auth/MSNT/smbdes.c
new file mode 100644 (file)
index 0000000..a9ac145
--- /dev/null
@@ -0,0 +1,364 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * 
+ * a partial implementation of DES designed for use in the 
+ * SMB authentication protocol
+ * 
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTES: 
+ * 
+ * This code makes no attempt to be fast! In fact, it is a very
+ * slow implementation 
+ * 
+ * This code is NOT a complete DES implementation. It implements only
+ * the minimum necessary for SMB authentication, as used by all SMB
+ * products (including every copy of Microsoft Windows95 ever sold)
+ * 
+ * In particular, it can only do a unchained forward DES pass. This
+ * means it is not possible to use this code for encryption/decryption
+ * of data, instead it is only useful as a "hash" algorithm.
+ * 
+ * There is no entry point into this code that allows normal DES operation.
+ * 
+ * I believe this means that this code does not come under ITAR
+ * regulations but this is NOT a legal opinion. If you are concerned
+ * about the applicability of ITAR regulations to this code then you
+ * should confirm it for yourself (and maybe let me know if you come
+ * up with a different answer to the one above)
+ */
+
+
+
+static int perm1[56] =
+{57, 49, 41, 33, 25, 17, 9,
+    1, 58, 50, 42, 34, 26, 18,
+    10, 2, 59, 51, 43, 35, 27,
+    19, 11, 3, 60, 52, 44, 36,
+    63, 55, 47, 39, 31, 23, 15,
+    7, 62, 54, 46, 38, 30, 22,
+    14, 6, 61, 53, 45, 37, 29,
+    21, 13, 5, 28, 20, 12, 4};
+
+static int perm2[48] =
+{14, 17, 11, 24, 1, 5,
+    3, 28, 15, 6, 21, 10,
+    23, 19, 12, 4, 26, 8,
+    16, 7, 27, 20, 13, 2,
+    41, 52, 31, 37, 47, 55,
+    30, 40, 51, 45, 33, 48,
+    44, 49, 39, 56, 34, 53,
+    46, 42, 50, 36, 29, 32};
+
+static int perm3[64] =
+{58, 50, 42, 34, 26, 18, 10, 2,
+    60, 52, 44, 36, 28, 20, 12, 4,
+    62, 54, 46, 38, 30, 22, 14, 6,
+    64, 56, 48, 40, 32, 24, 16, 8,
+    57, 49, 41, 33, 25, 17, 9, 1,
+    59, 51, 43, 35, 27, 19, 11, 3,
+    61, 53, 45, 37, 29, 21, 13, 5,
+    63, 55, 47, 39, 31, 23, 15, 7};
+
+static int perm4[48] =
+{32, 1, 2, 3, 4, 5,
+    4, 5, 6, 7, 8, 9,
+    8, 9, 10, 11, 12, 13,
+    12, 13, 14, 15, 16, 17,
+    16, 17, 18, 19, 20, 21,
+    20, 21, 22, 23, 24, 25,
+    24, 25, 26, 27, 28, 29,
+    28, 29, 30, 31, 32, 1};
+
+static int perm5[32] =
+{16, 7, 20, 21,
+    29, 12, 28, 17,
+    1, 15, 23, 26,
+    5, 18, 31, 10,
+    2, 8, 24, 14,
+    32, 27, 3, 9,
+    19, 13, 30, 6,
+    22, 11, 4, 25};
+
+
+static int perm6[64] =
+{40, 8, 48, 16, 56, 24, 64, 32,
+    39, 7, 47, 15, 55, 23, 63, 31,
+    38, 6, 46, 14, 54, 22, 62, 30,
+    37, 5, 45, 13, 53, 21, 61, 29,
+    36, 4, 44, 12, 52, 20, 60, 28,
+    35, 3, 43, 11, 51, 19, 59, 27,
+    34, 2, 42, 10, 50, 18, 58, 26,
+    33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static int sc[16] =
+{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static int sbox[8][4][16] =
+{
+    {
+       {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+       {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+       {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+       {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+    {
+       {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+       {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+       {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+       {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+    {
+       {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+       {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+       {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+       {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+    {
+       {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+       {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+       {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+       {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+    {
+       {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+       {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+       {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+       {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+    {
+       {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+       {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+       {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+       {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+    {
+       {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+       {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+       {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+       {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+    {
+       {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+       {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+       {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+       {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void
+permute(char *out, char *in, int *p, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = in[p[i] - 1];
+}
+
+static void
+lshift(char *d, int count, int n)
+{
+    char out[64];
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = d[(i + count) % n];
+    for (i = 0; i < n; i++)
+       d[i] = out[i];
+}
+
+static void
+concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+    while (l1--)
+       *out++ = *in1++;
+    while (l2--)
+       *out++ = *in2++;
+}
+
+static void
+xor(char *out, char *in1, char *in2, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = in1[i] ^ in2[i];
+}
+
+static void
+dohash(char *out, char *in, char *key)
+{
+    int i, j, k;
+    char pk1[56];
+    char c[28];
+    char d[28];
+    char cd[56];
+    char ki[16][48];
+    char pd1[64];
+    char l[32], r[32];
+    char rl[64];
+
+    permute(pk1, key, perm1, 56);
+
+    for (i = 0; i < 28; i++)
+       c[i] = pk1[i];
+    for (i = 0; i < 28; i++)
+       d[i] = pk1[i + 28];
+
+    for (i = 0; i < 16; i++) {
+       lshift(c, sc[i], 28);
+       lshift(d, sc[i], 28);
+
+       concat(cd, c, d, 28, 28);
+       permute(ki[i], cd, perm2, 48);
+    }
+
+    permute(pd1, in, perm3, 64);
+
+    for (j = 0; j < 32; j++) {
+       l[j] = pd1[j];
+       r[j] = pd1[j + 32];
+    }
+
+    for (i = 0; i < 16; i++) {
+       char er[48];
+       char erk[48];
+       char b[8][6];
+       char cb[32];
+       char pcb[32];
+       char r2[32];
+
+       permute(er, r, perm4, 48);
+
+       xor(erk, er, ki[i], 48);
+
+       for (j = 0; j < 8; j++)
+           for (k = 0; k < 6; k++)
+               b[j][k] = erk[j * 6 + k];
+
+       for (j = 0; j < 8; j++) {
+           int m, n;
+           m = (b[j][0] << 1) | b[j][5];
+
+           n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
+
+           for (k = 0; k < 4; k++)
+               b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
+       }
+
+       for (j = 0; j < 8; j++)
+           for (k = 0; k < 4; k++)
+               cb[j * 4 + k] = b[j][k];
+       permute(pcb, cb, perm5, 32);
+
+       xor(r2, l, pcb, 32);
+
+       for (j = 0; j < 32; j++)
+           l[j] = r[j];
+
+       for (j = 0; j < 32; j++)
+           r[j] = r2[j];
+    }
+
+    concat(rl, r, l, 32, 32);
+
+    permute(out, rl, perm6, 64);
+}
+
+static void
+str_to_key(unsigned char *str, unsigned char *key)
+{
+    int i;
+
+    key[0] = str[0] >> 1;
+    key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
+    key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
+    key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
+    key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
+    key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
+    key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
+    key[7] = str[6] & 0x7F;
+    for (i = 0; i < 8; i++) {
+       key[i] = (key[i] << 1);
+    }
+}
+
+
+static void
+smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    int i;
+    char outb[64];
+    char inb[64];
+    char keyb[64];
+    unsigned char key2[8];
+
+    str_to_key(key, key2);
+
+    for (i = 0; i < 64; i++) {
+       inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+       keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+       outb[i] = 0;
+    }
+
+    dohash(outb, inb, keyb);
+
+    for (i = 0; i < 8; i++) {
+       out[i] = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+       if (outb[i])
+           out[i / 8] |= (1 << (7 - (i % 8)));
+    }
+}
+
+void
+E_P16(unsigned char *p14, unsigned char *p16)
+{
+    unsigned char sp8[8] =
+    {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+    smbhash(p16, sp8, p14);
+    smbhash(p16 + 8, sp8, p14 + 7);
+}
+
+void
+E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+    smbhash(p24, c8, p21);
+    smbhash(p24 + 8, c8, p21 + 7);
+    smbhash(p24 + 16, c8, p21 + 14);
+}
+
+void
+cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+
+    smbhash(buf, in, key);
+    smbhash(out, buf, key + 9);
+}
+
+void
+cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+    static unsigned char key2[8];
+
+    smbhash(buf, in, key);
+    key2[0] = key[7];
+    smbhash(out, buf, key2);
+}
diff --git a/helpers/basic_auth/MSNT/smbencrypt.c b/helpers/basic_auth/MSNT/smbencrypt.c
new file mode 100644 (file)
index 0000000..0bd847f
--- /dev/null
@@ -0,0 +1,205 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1997
+ * Modified by Jeremy Allison 1995.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+/* Antonino #include <sys/vfs.h> */
+
+#include "smblib-priv.h"
+#define uchar unsigned char
+extern int DEBUGLEVEL;
+
+#include "byteorder.h"
+
+char *StrnCpy(char *dest, char *src, int n);
+void strupper(char *s);
+extern void E_P16(unsigned char *, unsigned char *);
+extern void E_P24(unsigned char *, unsigned char *, unsigned char *);
+extern void mdfour(unsigned char *, unsigned char *, int);
+
+
+/*
+ * This implements the X/Open SMB password encryption
+ * It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+ * encrypted password into p24 */
+void
+SMBencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p14[15], p21[21];
+
+    memset(p21, '\0', 21);
+    memset(p14, '\0', 14);
+    StrnCpy((char *) p14, (char *) passwd, 14);
+
+    strupper((char *) p14);
+    E_P16(p14, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(int16 * str)
+{
+    int len = 0;
+    while (*str++ != 0)
+       len++;
+    return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(int16 * dst, uchar * src, int len)
+{
+    int i;
+    int16 val;
+
+    for (i = 0; i < len; i++) {
+       val = *src;
+       SSVAL(dst, 0, val);
+       dst++;
+       src++;
+       if (val == 0)
+           break;
+    }
+    return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(uchar * passwd, uchar * p16)
+{
+    int len;
+    int16 wpwd[129];
+
+    /* Password cannot be longer than 128 characters */
+    len = strlen((char *) passwd);
+    if (len > 128)
+       len = 128;
+    /* Password must be converted to NT unicode */
+    _my_mbstowcs(wpwd, passwd, len);
+    wpwd[len] = 0;             /* Ensure string is null terminated */
+    /* Calculate length in bytes */
+    len = _my_wcslen(wpwd) * sizeof(int16);
+
+    mdfour(p16, (unsigned char *) wpwd, len);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p21[21];
+
+    memset(p21, '\0', 21);
+
+    E_md4hash(passwd, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+
+void
+nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+    char passwd[130];
+    StrnCpy(passwd, pwd, sizeof(passwd) - 1);
+
+    /* Calculate the MD4 hash (NT compatible) of the password */
+    memset(nt_p16, '\0', 16);
+    E_md4hash((uchar *) passwd, (uchar *) nt_p16);
+
+    /* Mangle the passwords into Lanman format */
+    passwd[14] = '\0';
+    strupper(passwd);
+
+    /* Calculate the SMB (lanman) hash functions of the password */
+
+    memset(p16, '\0', 16);
+    E_P16((uchar *) passwd, (uchar *) p16);
+
+    /* clear out local copy of user's password (just being paranoid). */
+    bzero(passwd, sizeof(passwd));
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *
+StrnCpy(char *dest, char *src, int n)
+{
+    char *d = dest;
+    if (!dest)
+       return (NULL);
+    if (!src) {
+       *dest = 0;
+       return (dest);
+    }
+    while (n-- && (*d++ = *src++));
+    *d = 0;
+    return (dest);
+}
+
+void
+strupper(char *s)
+{
+    while (*s) {
+#if UNUSED_CODE
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+       if (lp_client_code_page() == KANJI_CODEPAGE) {
+
+           if (is_shift_jis(*s)) {
+               if (is_sj_lower(s[0], s[1]))
+                   s[1] = sj_toupper2(s[1]);
+               s += 2;
+           } else if (is_kana(*s)) {
+               s++;
+           } else {
+               if (islower(*s))
+                   *s = toupper(*s);
+               s++;
+           }
+       } else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+#endif /* UNUSED_CODE */
+       {
+           if (islower(*s))
+               *s = toupper(*s);
+           s++;
+       }
+    }
+}
diff --git a/helpers/basic_auth/MSNT/smblib-common.h b/helpers/basic_auth/MSNT/smblib-common.h
new file mode 100644 (file)
index 0000000..b1ab26c
--- /dev/null
@@ -0,0 +1,189 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Common Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* To get the error class we want the first 8 bits */
+/* Because we just grab 4bytes from the SMB header, we have to re-order */
+/* here, but it makes the NtStatus part easier in future                */
+
+#ifndef _SMBLIB_COMMON_H_
+#define _SMBLIB_COMMON_H_
+
+#define SMBlib_Error_Class(p) (p & 0x000000FF)
+
+/* To get the error code, we want the bottom 16 bits */
+
+#define SMBlib_Error_Code(p) (((unsigned int)p & 0xFFFF0000) >>16)
+
+/* Error CLASS codes and etc ... */
+
+#define SMBC_SUCCESS        0
+#define SMBC_ERRDOS         0x01
+#define SMBC_ERRSRV         0x02
+#define SMBC_ERRHRD         0x03
+#define SMBC_ERRCMD         0xFF
+
+/* Success error codes    */
+
+#define SMBS_BUFFERED       0x54
+#define SMBS_LOGGED         0x55
+#define SMBS_DISPLAYED      0x56
+
+/* ERRDOS Error codes     */
+
+#define SMBD_badfunc        0x01
+#define SMBD_badfile        0x02
+#define SMBD_badpath        0x03
+#define SMBD_nofids         0x04
+#define SMBD_noaccess       0x05
+#define SMBD_badfid         0x06
+#define SMBD_badmcb         0x07
+#define SMBD_nomem          0x08
+#define SMBD_badmem         0x09
+#define SMBD_badenv         0x0A
+#define SMBD_badformat      0x0B
+#define SMBD_badaccess      0x0C
+#define SMBD_baddata        0x0D
+#define SMBD_reserved       0x0E
+#define SMBD_baddrive       0x0F
+#define SMBD_remcd          0x10
+#define SMBD_diffdevice     0x11
+#define SMBD_nofiles        0x12
+#define SMBD_badshare       0x20
+#define SMBD_errlock        0x21
+#define SMBD_filexists      0x50
+
+/* Server errors ... */
+
+#define SMBV_error          0x01       /* Generic error */
+#define SMBV_badpw          0x02
+#define SMBV_badtype        0x03
+#define SMBV_access         0x04
+#define SMBV_invnid         0x05
+#define SMBV_invnetname     0x06
+#define SMBV_invdevice      0x07
+#define SMBV_qfull          0x31
+#define SMBV_qtoobig        0x32
+#define SMBV_qeof           0x33
+#define SMBV_invpfid        0x34
+#define SMBV_paused         0x51
+#define SMBV_msgoff         0x52
+#define SMBV_noroom         0x53
+#define SMBV_rmuns          0x57
+#define SMBV_nosupport      0xFFFF
+
+/* Hardware error codes ... */
+
+#define SMBH_nowrite        0x13
+#define SMBH_badunit        0x14
+#define SMBH_notready       0x15
+#define SMBH_badcmd         0x16
+#define SMBH_data           0x17
+#define SMBH_badreq         0x18
+#define SMBH_seek           0x19
+#define SMBH_badmedia       0x1A
+#define SMBH_badsector      0x1B
+#define SMBH_nopaper        0x1C
+#define SMBH_write          0x1D
+#define SMBH_read           0x1E
+#define SMBH_general        0x1F
+#define SMBH_badshare       0x20
+
+/* Access mode defines ... */
+
+#define SMB_AMODE_WTRU      0x4000
+#define SMB_AMODE_NOCACHE   0x1000
+#define SMB_AMODE_COMPAT    0x0000
+#define SMB_AMODE_DENYRWX   0x0010
+#define SMB_AMODE_DENYW     0x0020
+#define SMB_AMODE_DENYRX    0x0030
+#define SMB_AMODE_DENYNONE  0x0040
+#define SMB_AMODE_OPENR     0x0000
+#define SMB_AMODE_OPENW     0x0001
+#define SMB_AMODE_OPENRW    0x0002
+#define SMB_AMODE_OPENX     0x0003
+#define SMB_AMODE_FCBOPEN   0x00FF
+#define SMB_AMODE_LOCUNKN   0x0000
+#define SMB_AMODE_LOCMSEQ   0x0100
+#define SMB_AMODE_LOCMRAN   0x0200
+#define SMB_AMODE_LOCRAL    0x0300
+
+/* File attribute encoding ... */
+
+#define SMB_FA_ORD          0x00
+#define SMB_FA_ROF          0x01
+#define SMB_FA_HID          0x02
+#define SMB_FA_SYS          0x04
+#define SMB_FA_VOL          0x08
+#define SMB_FA_DIR          0x10
+#define SMB_FA_ARC          0x20
+
+/* Define the protocol types ... */
+
+#define SMB_P_Unknown      -1  /* Hmmm, is this smart? */
+#define SMB_P_Core         0
+#define SMB_P_CorePlus     1
+#define SMB_P_DOSLanMan1   2
+#define SMB_P_LanMan1      3
+#define SMB_P_DOSLanMan2   4
+#define SMB_P_LanMan2      5
+#define SMB_P_DOSLanMan2_1 6
+#define SMB_P_LanMan2_1    7
+#define SMB_P_NT1          8
+
+/* SMBlib return codes */
+/* We want something that indicates whether or not the return code was a   */
+/* remote error, a local error in SMBlib or returned from lower layer ...  */
+/* Wonder if this will work ...                                            */
+/* SMBlibE_Remote = 1 indicates remote error                               */
+/* SMBlibE_ values < 0 indicate local error with more info available       */
+/* SMBlibE_ values >1 indicate local from SMBlib code errors?              */
+
+#define SMBlibE_Success 0
+#define SMBlibE_Remote  1      /* Remote error, get more info from con        */
+#define SMBlibE_BAD     -1
+#define SMBlibE_LowerLayer 2   /* Lower layer error                           */
+#define SMBlibE_NotImpl 3      /* Function not yet implemented                */
+#define SMBlibE_ProtLow 4      /* Protocol negotiated does not support req    */
+#define SMBlibE_NoSpace 5      /* No space to allocate a structure            */
+#define SMBlibE_BadParam 6     /* Bad parameters                              */
+#define SMBlibE_NegNoProt 7    /* None of our protocols was liked             */
+#define SMBlibE_SendFailed 8   /* Sending an SMB failed                       */
+#define SMBlibE_RecvFailed 9   /* Receiving an SMB failed                     */
+#define SMBlibE_GuestOnly 10   /* Logged in as guest                          */
+#define SMBlibE_CallFailed 11  /* Call remote end failed                     */
+#define SMBlibE_ProtUnknown 12 /* Protocol unknown                          */
+#define SMBlibE_NoSuchMsg  13  /* Keep this up to date                       */
+
+typedef struct {               /* A structure for a Dirent */
+
+    unsigned char resume_key[21];      /* Don't touch this          */
+    unsigned char file_attributes;     /* Attributes of file        */
+    unsigned int date_time;    /* date and time of last mod */
+    unsigned int size;
+    char filename[13];         /* The name of the file      */
+
+} SMB_CP_dirent;
+
+#endif /* _SMBLIB_COMMON_H_ */
diff --git a/helpers/basic_auth/MSNT/smblib-priv.h b/helpers/basic_auth/MSNT/smblib-priv.h
new file mode 100644 (file)
index 0000000..7caff4f
--- /dev/null
@@ -0,0 +1,604 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib private Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SMBLIB_PRIV_H_
+#define _SMBLIB_PRIV_H_
+
+#include "std-defines.h"
+#include "smblib-common.h"
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "byteorder.h"         /* Hmmm ... hot good */
+
+#define max(a,b) (a < b ? b : a)
+
+#define SMB_DEF_IDF 0x424D53FF /* "\377SMB" */
+
+/* Core protocol commands */
+
+#define SMBmkdir      0x00     /* create directory */
+#define SMBrmdir      0x01     /* delete directory */
+#define SMBopen       0x02     /* open file */
+#define SMBcreate     0x03     /* create file */
+#define SMBclose      0x04     /* close file */
+#define SMBflush      0x05     /* flush file */
+#define SMBunlink     0x06     /* delete file */
+#define SMBmv         0x07     /* rename file */
+#define SMBgetatr     0x08     /* get file attributes */
+#define SMBsetatr     0x09     /* set file attributes */
+#define SMBread       0x0A     /* read from file */
+#define SMBwrite      0x0B     /* write to file */
+#define SMBlock       0x0C     /* lock byte range */
+#define SMBunlock     0x0D     /* unlock byte range */
+#define SMBctemp      0x0E     /* create temporary file */
+#define SMBmknew      0x0F     /* make new file */
+#define SMBchkpth     0x10     /* check directory path */
+#define SMBexit       0x11     /* process exit */
+#define SMBlseek      0x12     /* seek */
+#define SMBtcon       0x70     /* tree connect */
+#define SMBtdis       0x71     /* tree disconnect */
+#define SMBnegprot    0x72     /* negotiate protocol */
+#define SMBdskattr    0x80     /* get disk attributes */
+#define SMBsearch     0x81     /* search directory */
+#define SMBsplopen    0xC0     /* open print spool file */
+#define SMBsplwr      0xC1     /* write to print spool file */
+#define SMBsplclose   0xC2     /* close print spool file */
+#define SMBsplretq    0xC3     /* return print queue */
+#define SMBsends      0xD0     /* send single block message */
+#define SMBsendb      0xD1     /* send broadcast message */
+#define SMBfwdname    0xD2     /* forward user name */
+#define SMBcancelf    0xD3     /* cancel forward */
+#define SMBgetmac     0xD4     /* get machine name */
+#define SMBsendstrt   0xD5     /* send start of multi-block message */
+#define SMBsendend    0xD6     /* send end of multi-block message */
+#define SMBsendtxt    0xD7     /* send text of multi-block message */
+
+/* CorePlus protocol                                        */
+
+#define SMBlockread   0x13     /* Lock a range and read it */
+#define SMBwriteunlock 0x14    /* Unlock a range and then write */
+#define SMBreadbraw   0x1a     /* read a block of data without smb header ohead */
+#define SMBwritebraw  0x1d     /* write a block of data without smb header ohead */
+#define SMBwritec     0x20     /* secondary write request */
+#define SMBwriteclose 0x2c     /* write a file and then close it */
+
+/* DOS Extended Protocol                                    */
+
+#define SMBreadBraw      0x1A  /* read block raw */
+#define SMBreadBmpx      0x1B  /* read block multiplexed */
+#define SMBreadBs        0x1C  /* read block (secondary response) */
+#define SMBwriteBraw     0x1D  /* write block raw */
+#define SMBwriteBmpx     0x1E  /* write block multiplexed */
+#define SMBwriteBs       0x1F  /* write block (secondary request) */
+#define SMBwriteC        0x20  /* write complete response */
+#define SMBsetattrE      0x22  /* set file attributes expanded */
+#define SMBgetattrE      0x23  /* get file attributes expanded */
+#define SMBlockingX      0x24  /* lock/unlock byte ranges and X */
+#define SMBtrans         0x25  /* transaction - name, bytes in/out */
+#define SMBtranss        0x26  /* transaction (secondary request/response) */
+#define SMBioctl         0x27  /* IOCTL */
+#define SMBioctls        0x28  /* IOCTL  (secondary request/response) */
+#define SMBcopy          0x29  /* copy */
+#define SMBmove          0x2A  /* move */
+#define SMBecho          0x2B  /* echo */
+#define SMBopenX         0x2D  /* open and X */
+#define SMBreadX         0x2E  /* read and X */
+#define SMBwriteX        0x2F  /* write and X */
+#define SMBsesssetupX    0x73  /* Session Set Up & X (including User Logon) */
+#define SMBtconX         0x75  /* tree connect and X */
+#define SMBffirst        0x82  /* find first */
+#define SMBfunique       0x83  /* find unique */
+#define SMBfclose        0x84  /* find close */
+#define SMBinvalid       0xFE  /* invalid command */
+
+/* Any more ? */
+
+#define SMBdatablockID     0x01        /* A data block identifier */
+#define SMBdialectID       0x02        /* A dialect id            */
+#define SMBpathnameID      0x03        /* A pathname ID           */
+#define SMBasciiID         0x04        /* An ascii string ID      */
+#define SMBvariableblockID 0x05        /* A variable block ID     */
+
+/* some other defines we need */
+
+/* Flags defines ... */
+
+#define SMB_FLG2_NON_DOS    0x01       /* We know non dos names             */
+#define SMB_FLG2_EXT_ATR    0x02       /* We know about Extended Attributes */
+#define SMB_FLG2_LNG_NAM    0x04       /* Long names ?                      */
+
+typedef unsigned short WORD;
+typedef unsigned short UWORD;
+typedef unsigned int ULONG;
+typedef unsigned char BYTE;
+typedef unsigned char UCHAR;
+
+/* Some macros to allow access to actual packet data so that we */
+/* can change the underlying representation of packets.         */
+/*                                                              */
+/* The current formats vying for attention are a fragment       */
+/* approach where the SMB header is a fragment linked to the    */
+/* data portion with the transport protocol (rfcnb or whatever) */
+/* being linked on the front.                                   */
+/*                                                              */
+/* The other approach is where the whole packet is one array    */
+/* of bytes with space allowed on the front for the packet      */
+/* headers.                                                     */
+
+#define SMB_Hdr(p) (char *)(p -> data)
+
+/* SMB Hdr def for File Sharing Protocol? From MS and Intel,    */
+/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also  */
+/* applies to LANMAN1.0 as well as the Core Protocol            */
+/* The spec states that wct and bcc must be present, even if 0  */
+
+/* We define these as offsets into a char SMB[] array for the   */
+/* sake of portability                                          */
+
+/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */
+/* the data that follows in the SMB packet, so the code will have to   */
+/* take that into account.                                             */
+
+#define SMB_hdr_idf_offset    0        /* 0xFF,'SMB' 0-3 */
+#define SMB_hdr_com_offset    4        /* BYTE       4   */
+#define SMB_hdr_rcls_offset   5        /* BYTE       5   */
+#define SMB_hdr_reh_offset    6        /* BYTE       6   */
+#define SMB_hdr_err_offset    7        /* WORD       7   */
+#define SMB_hdr_reb_offset    9        /* BYTE       9   */
+#define SMB_hdr_flg_offset    9        /* same as reb ... */
+#define SMB_hdr_res_offset    10       /* 7 WORDs    10  */
+#define SMB_hdr_res0_offset   10       /* WORD       10  */
+#define SMB_hdr_flg2_offset   10       /* WORD           */
+#define SMB_hdr_res1_offset   12       /* WORD       12  */
+#define SMB_hdr_res2_offset   14
+#define SMB_hdr_res3_offset   16
+#define SMB_hdr_res4_offset   18
+#define SMB_hdr_res5_offset   20
+#define SMB_hdr_res6_offset   22
+#define SMB_hdr_tid_offset    24
+#define SMB_hdr_pid_offset    26
+#define SMB_hdr_uid_offset    28
+#define SMB_hdr_mid_offset    30
+#define SMB_hdr_wct_offset    32
+
+#define SMB_hdr_len           33       /* 33 byte header?      */
+
+#define SMB_hdr_axc_offset    33       /* AndX Command         */
+#define SMB_hdr_axr_offset    34       /* AndX Reserved        */
+#define SMB_hdr_axo_offset    35       /* Offset from start to WCT of AndX cmd */
+
+/* Format of the Negotiate Protocol SMB */
+
+#define SMB_negp_bcc_offset   33
+#define SMB_negp_buf_offset   35       /* Where the buffer starts   */
+#define SMB_negp_len          35       /* plus the data             */
+
+/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */
+/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */
+/* for NT LM 0.12                                                    */
+
+#define SMB_negrCP_idx_offset   33     /* Response to the neg req */
+#define SMB_negrCP_bcc_offset   35
+#define SMB_negrLM_idx_offset   33     /* dialect index           */
+#define SMB_negrLM_sec_offset   35     /* Security mode           */
+#define SMB_sec_user_mask       0x01   /* 0 = share, 1 = user     */
+#define SMB_sec_encrypt_mask    0x02   /* pick out encrypt        */
+#define SMB_negrLM_mbs_offset   37     /* max buffer size         */
+#define SMB_negrLM_mmc_offset   39     /* max mpx count           */
+#define SMB_negrLM_mnv_offset   41     /* max number of VCs       */
+#define SMB_negrLM_rm_offset    43     /* raw mode support bit vec */
+#define SMB_read_raw_mask       0x01
+#define SMB_write_raw_mask      0x02
+#define SMB_negrLM_sk_offset    45     /* session key, 32 bits    */
+#define SMB_negrLM_st_offset    49     /* Current server time     */
+#define SMB_negrLM_sd_offset    51     /* Current server date     */
+#define SMB_negrLM_stz_offset   53     /* Server Time Zone        */
+#define SMB_negrLM_ekl_offset   55     /* encryption key length   */
+#define SMB_negrLM_res_offset   57     /* reserved                */
+#define SMB_negrLM_bcc_offset   59     /* bcc                     */
+#define SMB_negrLM_len          61     /* 61 bytes ?              */
+#define SMB_negrLM_buf_offset   61     /* Where the fun begins    */
+
+#define SMB_negrNTLM_idx_offset 33     /* Selected protocol       */
+#define SMB_negrNTLM_sec_offset 35     /* Security more           */
+#define SMB_negrNTLM_mmc_offset 36     /* Different format above  */
+#define SMB_negrNTLM_mnv_offset 38     /* Max VCs                 */
+#define SMB_negrNTLM_mbs_offset 40     /* MBS now a long          */
+#define SMB_negrNTLM_mrs_offset 44     /* Max raw size            */
+#define SMB_negrNTLM_sk_offset  48     /* Session Key             */
+#define SMB_negrNTLM_cap_offset 52     /* Capabilities            */
+#define SMB_negrNTLM_stl_offset 56     /* Server time low         */
+#define SMB_negrNTLM_sth_offset 60     /* Server time high        */
+#define SMB_negrNTLM_stz_offset 64     /* Server time zone        */
+#define SMB_negrNTLM_ekl_offset 66     /* Encrypt key len         */
+#define SMB_negrNTLM_bcc_offset 67     /* Bcc                     */
+#define SMB_negrNTLM_len        69
+#define SMB_negrNTLM_buf_offset 69
+
+/* Offsets related to Tree Connect                                      */
+
+#define SMB_tcon_bcc_offset     33
+#define SMB_tcon_buf_offset     35     /* where the data is for tcon */
+#define SMB_tcon_len            35     /* plus the data              */
+
+#define SMB_tconr_mbs_offset    33     /* max buffer size         */
+#define SMB_tconr_tid_offset    35     /* returned tree id        */
+#define SMB_tconr_bcc_offset    37
+#define SMB_tconr_len           39
+
+#define SMB_tconx_axc_offset    33     /* And X Command                */
+#define SMB_tconx_axr_offset    34     /* reserved                     */
+#define SMB_tconx_axo_offset    35     /* Next command offset          */
+#define SMB_tconx_flg_offset    37     /* Flags, bit0=1 means disc TID */
+#define SMB_tconx_pwl_offset    39     /* Password length              */
+#define SMB_tconx_bcc_offset    41     /* bcc                          */
+#define SMB_tconx_buf_offset    43     /* buffer                       */
+#define SMB_tconx_len           43     /* up to data ...               */
+
+#define SMB_tconxr_axc_offset   33     /* Where the AndX Command is    */
+#define SMB_tconxr_axr_offset   34     /* Reserved                     */
+#define SMB_tconxr_axo_offset   35     /* AndX offset location         */
+
+/* Offsets related to tree_disconnect                                  */
+
+#define SMB_tdis_bcc_offset     33     /* bcc                     */
+#define SMB_tdis_len            35     /* total len               */
+
+#define SMB_tdisr_bcc_offset    33     /* bcc                     */
+#define SMB_tdisr_len           35
+
+/* Offsets related to Open Request                                     */
+
+#define SMB_open_mod_offset     33     /* Mode to open with       */
+#define SMB_open_atr_offset     35     /* Attributes of file      */
+#define SMB_open_bcc_offset     37     /* bcc                     */
+#define SMB_open_buf_offset     39     /* File name               */
+#define SMB_open_len            39     /* Plus the file name      */
+
+#define SMB_openx_axc_offset    33     /* Next command            */
+#define SMB_openx_axr_offset    34     /* Reserved                */
+#define SMB_openx_axo_offset    35     /* offset of next wct      */
+#define SMB_openx_flg_offset    37     /* Flags, bit0 = need more info */
+                                         /* bit1 = exclusive oplock */
+                                         /* bit2 = batch oplock     */
+#define SMB_openx_mod_offset    39     /* mode to open with       */
+#define SMB_openx_atr_offset    41     /* search attributes       */
+#define SMB_openx_fat_offset    43     /* File attributes         */
+#define SMB_openx_tim_offset    45     /* time and date of creat  */
+#define SMB_openx_ofn_offset    49     /* Open function           */
+#define SMB_openx_als_offset    51     /* Space to allocate on    */
+#define SMB_openx_res_offset    55     /* reserved                */
+#define SMB_openx_bcc_offset    63     /* bcc                     */
+#define SMB_openx_buf_offset    65     /* Where file name goes    */
+#define SMB_openx_len           65
+
+#define SMB_openr_fid_offset    33     /* FID returned            */
+#define SMB_openr_atr_offset    35     /* Attributes opened with  */
+#define SMB_openr_tim_offset    37     /* Last mod time of file   */
+#define SMB_openr_fsz_offset    41     /* File size 4 bytes       */
+#define SMB_openr_acc_offset    45     /* Access allowed          */
+#define SMB_openr_bcc_offset    47
+#define SMB_openr_len           49
+
+#define SMB_openxr_axc_offset   33     /* And X command           */
+#define SMB_openxr_axr_offset   34     /* reserved                */
+#define SMB_openxr_axo_offset   35     /* offset to next command  */
+#define SMB_openxr_fid_offset   37     /* FID returned            */
+#define SMB_openxr_fat_offset   39     /* File attributes returned */
+#define SMB_openxr_tim_offset   41     /* File creation date etc  */
+#define SMB_openxr_fsz_offset   45     /* Size of file            */
+#define SMB_openxr_acc_offset   49     /* Access granted          */
+
+#define SMB_clos_fid_offset     33     /* FID to close            */
+#define SMB_clos_tim_offset     35     /* Last mod time           */
+#define SMB_clos_bcc_offset     39     /* bcc                     */
+#define SMB_clos_len            41
+
+/* Offsets related to Write requests                                 */
+
+#define SMB_write_fid_offset    33     /* FID to write            */
+#define SMB_write_cnt_offset    35     /* bytes to write          */
+#define SMB_write_ofs_offset    37     /* location to write to    */
+#define SMB_write_clf_offset    41     /* advisory count left     */
+#define SMB_write_bcc_offset    43     /* bcc = data bytes + 3    */
+#define SMB_write_buf_offset    45     /* Data=0x01, len, data    */
+#define SMB_write_len           45     /* plus the data ...       */
+
+#define SMB_writr_cnt_offset    33     /* Count of bytes written  */
+#define SMB_writr_bcc_offset    35     /* bcc                     */
+#define SMB_writr_len           37
+
+/* Offsets related to read requests */
+
+#define SMB_read_fid_offset     33     /* FID of file to read     */
+#define SMB_read_cnt_offset     35     /* count of words to read  */
+#define SMB_read_ofs_offset     37     /* Where to read from      */
+#define SMB_read_clf_offset     41     /* Advisory count to go    */
+#define SMB_read_bcc_offset     43
+#define SMB_read_len            45
+
+#define SMB_readr_cnt_offset    33     /* Count of bytes returned */
+#define SMB_readr_res_offset    35     /* 4 shorts reserved, 8 bytes */
+#define SMB_readr_bcc_offset    43     /* bcc                     */
+#define SMB_readr_bff_offset    45     /* buffer format char = 0x01 */
+#define SMB_readr_len_offset    46     /* buffer len              */
+#define SMB_readr_len           45     /* length of the readr before data */
+
+/* Offsets for Create file                                           */
+
+#define SMB_creat_atr_offset    33     /* Attributes of new file ... */
+#define SMB_creat_tim_offset    35     /* Time of creation           */
+#define SMB_creat_dat_offset    37     /* 4004BCE :-)                */
+#define SMB_creat_bcc_offset    39     /* bcc                        */
+#define SMB_creat_buf_offset    41
+#define SMB_creat_len           41     /* Before the data            */
+
+#define SMB_creatr_fid_offset   33     /* FID of created file        */
+
+/* Offsets for Delete file                                           */
+
+#define SMB_delet_sat_offset    33     /* search attribites          */
+#define SMB_delet_bcc_offset    35     /* bcc                        */
+#define SMB_delet_buf_offset    37
+#define SMB_delet_len           37
+
+/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols    */
+
+#define SMB_ssetpLM_mbs_offset  37     /* Max buffer Size, allow for AndX */
+#define SMB_ssetpLM_mmc_offset  39     /* max multiplex count             */
+#define SMB_ssetpLM_vcn_offset  41     /* VC number if new VC             */
+#define SMB_ssetpLM_snk_offset  43     /* Session Key                     */
+#define SMB_ssetpLM_pwl_offset  47     /* password length                 */
+#define SMB_ssetpLM_res_offset  49     /* reserved                        */
+#define SMB_ssetpLM_bcc_offset  53     /* bcc                             */
+#define SMB_ssetpLM_len         55     /* before data ...                 */
+#define SMB_ssetpLM_buf_offset  55
+
+#define SMB_ssetpNTLM_mbs_offset 37    /* Max Buffer Size for NT LM 0.12  */
+                                         /* and above                       */
+#define SMB_ssetpNTLM_mmc_offset 39    /* Max Multiplex count             */
+#define SMB_ssetpNTLM_vcn_offset 41    /* VC Number                       */
+#define SMB_ssetpNTLM_snk_offset 43    /* Session key                     */
+#define SMB_ssetpNTLM_cipl_offset 47   /* Case Insensitive PW Len         */
+#define SMB_ssetpNTLM_cspl_offset 49   /* Unicode pw len                  */
+#define SMB_ssetpNTLM_res_offset 51    /* reserved                        */
+#define SMB_ssetpNTLM_cap_offset 55    /* server capabilities             */
+#define SMB_ssetpNTLM_bcc_offset 59    /* bcc                             */
+#define SMB_ssetpNTLM_len        61    /* before data                     */
+#define SMB_ssetpNTLM_buf_offset 61
+
+#define SMB_ssetpr_axo_offset  35      /* Offset of next response ...    */
+#define SMB_ssetpr_act_offset  37      /* action, bit 0 = 1 => guest     */
+#define SMB_ssetpr_bcc_offset  39      /* bcc                            */
+#define SMB_ssetpr_buf_offset  41      /* Native OS etc                  */
+
+/* Offsets for SMB create directory                                         */
+
+#define SMB_creatdir_bcc_offset 33     /* only a bcc here                */
+#define SMB_creatdir_buf_offset 35     /* Where things start             */
+#define SMB_creatdir_len        35
+
+/* Offsets for SMB delete directory                                         */
+
+#define SMB_deletdir_bcc_offset 33     /* only a bcc here                */
+#define SMB_deletdir_buf_offset 35     /* where things start             */
+#define SMB_deletdir_len        35
+
+/* Offsets for SMB check directory                                          */
+
+#define SMB_checkdir_bcc_offset 33     /* Only a bcc here                */
+#define SMB_checkdir_buf_offset 35     /* where things start             */
+#define SMB_checkdir_len        35
+
+/* Offsets for SMB search                                                   */
+
+#define SMB_search_mdc_offset   33     /* Max Dir ents to return         */
+#define SMB_search_atr_offset   35     /* Search attributes              */
+#define SMB_search_bcc_offset   37     /* bcc                            */
+#define SMB_search_buf_offset   39     /* where the action is            */
+#define SMB_search_len          39
+
+#define SMB_searchr_dec_offset  33     /* Dir ents returned              */
+#define SMB_searchr_bcc_offset  35     /* bcc                            */
+#define SMB_searchr_buf_offset  37     /* Where the action starts        */
+#define SMB_searchr_len         37     /* before the dir ents            */
+
+#define SMB_searchr_dirent_len  43     /* 53 bytes                       */
+
+/* Defines for SMB transact and transact2 calls                             */
+
+#define SMB_trans_tpc_offset    33     /* Total param count              */
+#define SMB_trans_tdc_offset    35     /* total Data count               */
+#define SMB_trans_mpc_offset    37     /* Max params bytes to return     */
+#define SMB_trans_mdc_offset    39     /* Max data bytes to return       */
+#define SMB_trans_msc_offset    41     /* Max setup words to return      */
+#define SMB_trans_rs1_offset    42     /* Reserved byte                  */
+#define SMB_trans_flg_offset    43     /* flags                          */
+#define SMB_trans_tmo_offset    45     /* Timeout, long                  */
+#define SMB_trans_rs2_offset    49     /* Next reserved                  */
+#define SMB_trans_pbc_offset    51     /* Param Byte count in buf        */
+#define SMB_trans_pbo_offset    53     /* Offset to param bytes          */
+#define SMB_trans_dbc_offset    55     /* Data byte count in buf         */
+#define SMB_trans_dbo_offset    57     /* Data byte offset               */
+#define SMB_trans_suc_offset    59     /* Setup count - byte             */
+#define SMB_trans_rs3_offset    60     /* Reserved to pad ...            */
+#define SMB_trans_len           61     /* Up to setup, still need bcc    */
+
+#define SMB_transr_tpc_offset   33     /* Total param bytes returned     */
+#define SMB_transr_tdc_offset   35
+#define SMB_transr_rs1_offset   37
+#define SMB_transr_pbc_offset   39
+#define SMB_transr_pbo_offset   41
+#define SMB_transr_pdi_offset   43     /* parameter displacement         */
+#define SMB_transr_dbc_offset   45
+#define SMB_transr_dbo_offset   47
+#define SMB_transr_ddi_offset   49
+#define SMB_transr_suc_offset   51
+#define SMB_transr_rs2_offset   52
+#define SMB_transr_len          53
+
+/* Bit masks for SMB Capabilities ...                       */
+
+#define SMB_cap_raw_mode         0x0001
+#define SMB_cap_mpx_mode         0x0002
+#define SMB_cap_unicode          0x0004
+#define SMB_cap_large_files      0x0008
+#define SMB_cap_nt_smbs          0x0010
+#define SMB_rpc_remote_apis      0x0020
+#define SMB_cap_nt_status        0x0040
+#define SMB_cap_level_II_oplocks 0x0080
+#define SMB_cap_lock_and_read    0x0100
+#define SMB_cap_nt_find          0x0200
+
+/* SMB LANMAN api call defines */
+
+#define SMB_LMapi_SetUserInfo     0x0072
+#define SMB_LMapi_UserPasswordSet 0x0073
+
+/* Structures and defines we use in the client interface */
+
+/* The protocols we might support. Perhaps a bit ambitious, as only RFCNB */
+/* has any support so far 0(sometimes called NBT)                         */
+
+typedef enum {
+    SMB_RFCNB, SMB_IPXNB, SMB_NETBEUI, SMB_X25
+} SMB_Transport_Types;
+
+typedef enum {
+    SMB_Con_FShare, SMB_Con_PShare, SMB_Con_IPC
+} SMB_Con_Types;
+
+typedef enum {
+    SMB_State_NoState, SMB_State_Stopped, SMB_State_Started
+} SMB_State_Types;
+
+/* The following two arrays need to be in step!              */
+/* We must make it possible for callers to specify these ... */
+
+
+extern char *SMB_Prots[];
+extern int SMB_Types[];
+
+typedef struct SMB_Status {
+
+    union {
+       struct {
+           unsigned char ErrorClass;
+           unsigned char Reserved;
+           unsigned short Error;
+       } DosError;
+       unsigned int NtStatus;
+    } status;
+} SMB_Status;
+
+typedef struct SMB_Tree_Structure *SMB_Tree_Handle;
+
+typedef struct SMB_Connect_Def *SMB_Handle_Type;
+
+struct SMB_Connect_Def {
+
+    SMB_Handle_Type Next_Con, Prev_Con;                /* Next and previous conn */
+    int protocol;              /* What is the protocol   */
+    int prot_IDX;              /* And what is the index  */
+    void *Trans_Connect;       /* The connection         */
+
+    /* All these strings should be malloc'd */
+
+    char service[80], username[80], password[80], desthost[80], sock_options[80];
+    char address[80], myname[80];
+
+    SMB_Tree_Handle first_tree, last_tree;     /* List of trees on this server */
+
+    int gid;                   /* Group ID, do we need it?                      */
+    int mid;                   /* Multiplex ID? We might need one per con       */
+    int pid;                   /* Process ID                                    */
+
+    int uid;                   /* Authenticated user id.                        */
+
+    /* It is pretty clear that we need to bust some of */
+    /* these out into a per TCon record, as there may  */
+    /* be multiple TCon's per server, etc ... later    */
+
+    int port;                  /* port to use in case not default, this is a TCPism! */
+
+    int max_xmit;              /* Max xmit permitted by server                  */
+    int Security;              /* 0 = share, 1 = user                           */
+    int Raw_Support;           /* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */
+    BOOL encrypt_passwords;    /* FALSE = don't                          */
+    int MaxMPX, MaxVC, MaxRaw;
+    unsigned int SessionKey, Capabilities;
+    int SvrTZ;                 /* Server Time Zone */
+    int Encrypt_Key_Len;
+    char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40];
+    char Svr_OS[80], Svr_LMType[80], Svr_PDom[80];
+
+};
+
+#define SMBLIB_DEFAULT_DOMAIN "STAFF"
+#define SMBLIB_DEFAULT_OSNAME "UNIX of some type"
+#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit"
+#define SMBLIB_MAX_XMIT 65535
+
+#define SMB_Sec_Mode_Share 0
+#define SMB_Sec_Mode_User  1
+
+/* A Tree_Structure                       */
+
+struct SMB_Tree_Structure {
+
+    SMB_Tree_Handle next, prev;
+    SMB_Handle_Type con;
+    char path[129];
+    char device_type[20];
+    int mbs;                   /* Local MBS */
+    int tid;
+
+};
+
+typedef struct SMB_File_Def SMB_File;
+
+struct SMB_File_Def {
+
+    SMB_Tree_Handle tree;
+    char filename[256];                /* We should malloc this ... */
+    UWORD fid;
+    unsigned int lastmod;
+    unsigned int size;         /* Could blow up if 64bit files supported */
+    UWORD access;
+    off_t fileloc;
+
+};
+
+/* global Variables for the library */
+
+extern SMB_State_Types SMBlib_State;
+
+#ifndef SMBLIB_ERRNO
+extern int SMBlib_errno;
+extern int SMBlib_SMB_Error;   /* last Error             */
+#endif
+
+#endif /* _SMBLIB_PRIV_H_ */
diff --git a/helpers/basic_auth/MSNT/smblib-util.c b/helpers/basic_auth/MSNT/smblib-util.c
new file mode 100644 (file)
index 0000000..f4f8026
--- /dev/null
@@ -0,0 +1,803 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Utility Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "smblib-priv.h"
+
+#include "rfcnb.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL};
+
+int SMB_Types[] =
+{SMB_P_Core,
+    SMB_P_CorePlus,
+    SMB_P_DOSLanMan1,
+    SMB_P_DOSLanMan1,
+    SMB_P_LanMan1,
+    SMB_P_DOSLanMan2,
+    SMB_P_LanMan2,
+    SMB_P_LanMan2_1,
+    SMB_P_LanMan2_1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    -1};
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void
+SMB_Print_Pkt(FILE fd, RFCNB_Pkt * pkt, BOOL command, int Offset, int Len)
+{
+
+    /* Well, just how do we do this ... print it I suppose */
+
+    /* Print out the SMB header ...                        */
+
+    /* Print the command                                   */
+
+    /* Print the other bits in the header                  */
+
+
+    /* etc                                                 */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *
+SMB_DOSTimToStr(int DOS_time)
+{
+    static char SMB_Time_Temp[48];
+    int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+    SMB_Time_Temp[0] = 0;
+
+    DOS_sec = (DOS_time & 0x001F) * 2;
+    DOS_min = (DOS_time & 0x07E0) >> 5;
+    DOS_hour = ((DOS_time & 0xF800) >> 11);
+
+    DOS_day = (DOS_time & 0x001F0000) >> 16;
+    DOS_month = (DOS_time & 0x01E00000) >> 21;
+    DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+    sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+       DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+    return (SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+ * to a static string which we guarantee is long enough. If verbose is 
+ * true, we print out long form of strings ...                            */
+
+char *
+SMB_AtrToStr(int attribs, BOOL verbose)
+{
+    static char SMB_Attrib_Temp[128];
+
+    SMB_Attrib_Temp[0] = 0;
+
+    if (attribs & SMB_FA_ROF)
+       strcat(SMB_Attrib_Temp, (verbose ? "Read Only " : "R"));
+
+    if (attribs & SMB_FA_HID)
+       strcat(SMB_Attrib_Temp, (verbose ? "Hidden " : "H"));
+
+    if (attribs & SMB_FA_SYS)
+       strcat(SMB_Attrib_Temp, (verbose ? "System " : "S"));
+
+    if (attribs & SMB_FA_VOL)
+       strcat(SMB_Attrib_Temp, (verbose ? "Volume " : "V"));
+
+    if (attribs & SMB_FA_DIR)
+       strcat(SMB_Attrib_Temp, (verbose ? "Directory " : "D"));
+
+    if (attribs & SMB_FA_ARC)
+       strcat(SMB_Attrib_Temp, (verbose ? "Archive " : "A"));
+
+    return (SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int
+SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+{
+    if (tree != NULL) {
+       return (tree->mbs);
+    } else {
+       return (SMBlibE_BAD);
+    }
+}
+
+/* Pick up the Max buffer size */
+
+int
+SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->max_xmit);
+    } else {
+       return (SMBlibE_BAD);
+    }
+
+}
+/* Pickup the protocol index from the connection structure                 */
+
+int
+SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->prot_IDX);
+    } else {
+       return (0xFFFF);        /* Invalid protocol */
+    }
+
+}
+
+/* Pick up the protocol from the connection structure                       */
+
+int
+SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->protocol);
+    } else {
+       return (0xFFFF);        /* Invalid protocol */
+    }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user      */
+/* supplied list, and assume that it is a subset of our list                */
+
+int
+SMB_Figure_Protocol(char *dialects[], int prot_index)
+{
+    int i;
+
+    if (dialects == SMB_Prots) {       /* The jobs is easy, just index into table */
+
+       return (SMB_Types[prot_index]);
+    } else {                   /* Search through SMB_Prots looking for a match */
+
+       for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+           if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) {      /* A match */
+
+               return (SMB_Types[i]);
+
+           }
+       }
+
+       /* If we got here, then we are in trouble, because the protocol was not */
+       /* One we understand ...                                                */
+
+       return (SMB_P_Unknown);
+
+    }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots       */
+/* we return the index of the accepted protocol in NegProt, -1 indicates  */
+/* none acceptible, and our return value is 0 if ok, <0 if problems       */
+
+int
+SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+{
+    struct RFCNB_Pkt *pkt;
+    int prots_len, i, pkt_len, prot, alloc_len;
+    char *p;
+
+    /* Figure out how long the prot list will be and allocate space for it */
+
+    prots_len = 0;
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+       prots_len = prots_len + strlen(Prots[i]) + 2;   /* Account for null etc */
+
+    }
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_negp_len + prots_len;
+
+    /* Make sure that the pkt len is long enough for the max response ...   */
+    /* Which is a problem, because the encryption key len eec may be long   */
+
+    if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+       alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+    } else {
+
+       alloc_len = pkt_len;
+
+    }
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(alloc_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now plug in the bits we need */
+
+    bzero(SMB_Hdr(pkt), SMB_negp_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+    /* Now copy the prot strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+       *p = SMBdialectID;
+       strcpy(p + 1, Prots[i]);
+       p = p + strlen(Prots[i]) + 2;   /* Adjust len of p for null plus dialectID */
+
+    }
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;     /* Failed, check lower layer errno */
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;     /* Failed, check lower layer errno */
+       return (SMBlibE_BAD);
+
+    }
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+    if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+       fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_NegNoProt;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now, unpack the info from the response, if any and evaluate the proto */
+    /* selected. We must make sure it is one we like ...                     */
+
+    Con_Handle->prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+    Con_Handle->protocol = SMB_Figure_Protocol(Prots, prot);
+
+    if (Con_Handle->protocol == SMB_P_Unknown) {       /* No good ... */
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_ProtUnknown;
+       return (SMBlibE_BAD);
+
+    }
+    switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+    case 0x01:                 /* No more info ... */
+
+       break;
+
+    case 13:                   /* Up to and including LanMan 2.1 */
+
+       Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+       Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+       Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+       Con_Handle->max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+       Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+       Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+       Con_Handle->Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+       Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+       Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+       Con_Handle->Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+
+       p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
+       fprintf(stderr, "%d", (int) (SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
+       memcpy(Con_Handle->Encrypt_Key, p, 8);
+
+       p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+       strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+       break;
+
+    case 17:                   /* NT LM 0.12 and LN LM 1.0 */
+
+       Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+       Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+       Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+       Con_Handle->max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+       Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+       Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+       Con_Handle->MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+       Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+       Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+       Con_Handle->Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+       p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset);
+       memcpy(Con_Handle->Encrypt_Key, p, 8);
+       p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+       strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+       break;
+
+    default:
+
+#ifdef DEBUG
+       fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+       fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+       break;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Get our hostname */
+
+void
+SMB_Get_My_Name(char *name, int len)
+{
+
+    if (gethostname(name, len) < 0) {  /* Error getting name */
+
+       strncpy(name, "unknown", len);
+
+       /* Should check the error */
+
+#ifdef DEBUG
+       fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+       perror("");
+#endif
+
+    }
+    /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ...               */
+
+SMB_Tree_Handle
+SMB_TreeConnect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle Tree_Handle,
+    char *path,
+    char *password,
+    char *device)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len;
+    char *p;
+    SMB_Tree_Handle tree;
+
+    /* Figure out how much space is needed for path, password, dev ... */
+
+    if ((path == NULL) | (password == NULL) | (device == NULL)) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+       SMBlib_errno = SMBlibE_BadParam;
+       return (NULL);
+
+    }
+    /* The + 2 is because of the \0 and the marker ...                    */
+
+    param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_tcon_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (NULL);          /* Should handle the error */
+
+    }
+    /* Now allocate a tree for this to go into ... */
+
+    if (Tree_Handle == NULL) {
+
+       tree = (SMB_Tree_Handle) malloc(sizeof(struct SMB_Tree_Structure));
+
+       if (tree == NULL) {
+
+           RFCNB_Free_Pkt(pkt);
+           SMBlib_errno = SMBlibE_NoSpace;
+           return (NULL);
+
+       }
+    } else {
+
+       tree = Tree_Handle;
+
+    }
+
+    tree->next = tree->prev = NULL;
+    tree->con = Con_Handle;
+    strncpy(tree->path, path, sizeof(tree->path));
+    strncpy(tree->device_type, device, sizeof(tree->device_type));
+
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tcon_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+    *p = SMBasciiID;
+    strcpy(p + 1, path);
+    p = p + strlen(path) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, password);
+    p = p + strlen(password) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, device);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;
+       return (NULL);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;
+       return (NULL);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (NULL);
+
+    }
+    tree->tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+    tree->mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+    fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+       tree->tid, tree->mbs);
+#endif
+
+    /* Now link the Tree to the Server Structure ... */
+
+    if (Con_Handle->first_tree == NULL) {
+
+       Con_Handle->first_tree = tree;
+       Con_Handle->last_tree = tree;
+
+    } else {
+
+       Con_Handle->last_tree->next = tree;
+       tree->prev = Con_Handle->last_tree;
+       Con_Handle->last_tree = tree;
+
+    }
+
+    RFCNB_Free_Pkt(pkt);
+    return (tree);
+
+}
+
+int
+SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+{
+    struct RFCNB_Pkt *pkt;
+    int pkt_len;
+
+    pkt_len = SMB_tdis_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (SMBlibE_BAD);   /* Should handle the error */
+
+    }
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tdis_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle->con->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle->con->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle->con->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle->tid);
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+    Tree_Handle->tid = 0xFFFF; /* Invalid TID */
+    Tree_Handle->mbs = 0;      /* Invalid     */
+
+#ifdef DEBUG
+
+    fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+    /* What about the tree handle ? */
+
+    if (discard == TRUE) {     /* Unlink it and free it ... */
+
+       if (Tree_Handle->next == NULL)
+           Tree_Handle->con->first_tree = Tree_Handle->prev;
+       else
+           Tree_Handle->next->prev = Tree_Handle->prev;
+
+       if (Tree_Handle->prev == NULL)
+           Tree_Handle->con->last_tree = Tree_Handle->next;
+       else
+           Tree_Handle->prev->next = Tree_Handle->next;
+
+    }
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int
+SMB_Get_Last_Error()
+{
+
+    return (SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet          */
+/* We will need macros to extract error class and error code */
+
+int
+SMB_Get_Last_SMB_Err()
+{
+
+    return (SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib  */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] =
+{
+
+    "Request completed sucessfully.",
+    "Server returned a non-zero SMB Error Class and Code.",
+    "A lower layer protocol error occurred.",
+    "Function not yet implemented.",
+    "The protocol negotiated does not support the request.",
+    "No space available for operation.",
+    "One or more bad parameters passed.",
+    "None of the protocols we offered were accepted.",
+    "The attempt to send an SMB request failed. See protocol error info.",
+    "The attempt to get an SMB response failed. See protocol error info.",
+    "The logon request failed, but you were logged in as guest.",
+    "The attempt to call the remote server failed. See protocol error info.",
+    "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+  /* This next one simplifies error handling */
+    "No such error code.",
+    NULL};
+
+void
+SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+{
+
+    if (msg >= 0) {
+
+       strncpy(msgbuf,
+           SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+           len - 1);
+       msgbuf[len - 1] = 0;    /* Make sure it is a string */
+    } else {                   /* Add the lower layer message ... */
+
+       char prot_msg[1024];
+
+       msg = -msg;             /* Make it positive */
+
+       strncpy(msgbuf,
+           SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+           len - 1);
+
+       msgbuf[len - 1] = 0;    /* make sure it is a string */
+
+       if (strlen(msgbuf) < len) {     /* If there is space, put rest in */
+
+           strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+           RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+           strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+       }
+    }
+
+}
diff --git a/helpers/basic_auth/MSNT/smblib.c b/helpers/basic_auth/MSNT/smblib.c
new file mode 100644 (file)
index 0000000..725b026
--- /dev/null
@@ -0,0 +1,555 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int SMBlib_errno;
+int SMBlib_SMB_Error;
+#define SMBLIB_ERRNO
+#define uchar unsigned char
+#include "smblib-priv.h"
+#include "smblib.h"
+#include "rfcnb-priv.h"
+#include "rfcnb.h"
+#include "rfcnb-util.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <signal.h>
+
+SMB_State_Types SMBlib_State;
+
+extern int RFCNB_Set_Sock_NoDelay(RFCNB_Con *, BOOL);
+extern void SMB_Get_My_Name(char *, int);
+
+/* Initialize the SMBlib package     */
+
+int
+SMB_Init()
+{
+
+    SMBlib_State = SMB_State_Started;
+
+    signal(SIGPIPE, SIG_IGN);  /* Ignore these ... */
+
+/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Init();
+
+#endif
+
+    return 0;
+
+}
+
+int
+SMB_Term()
+{
+
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Term();  /* Clean up and print results */
+
+#endif
+
+    return 0;
+
+}
+
+/* SMB_Create: Create a connection structure and return for later use */
+/* We have other helper routines to set variables                     */
+
+SMB_Handle_Type
+SMB_Create_Con_Handle(void)
+{
+
+    SMBlib_errno = SMBlibE_NotImpl;
+    return (NULL);
+
+}
+
+int
+SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
+{
+
+
+    if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
+
+#ifdef DEBUG
+#endif
+
+       fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
+
+    }
+    return (0);
+
+}
+
+/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
+/* or anything else ...                                                  */
+
+SMB_Handle_Type
+SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+    char *server, char *NTdomain)
+{
+    SMB_Handle_Type con;
+    char called[80], calling[80], *address;
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+       if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return NULL;
+       }
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, "");
+    strcpy(con->username, "");
+    strcpy(con->password, "");
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->desthost, server);
+    strcpy(con->PDomain, NTdomain);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;             /* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;       /* This will do for now ... */
+    con->uid = 0;              /* Until we have done a logon, no uid ... */
+    con->gid = getgid();
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(server); i++)
+       called[i] = toupper(server[i]);
+
+    called[strlen(server)] = 0;        /* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+       calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;  /* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+       address = con->desthost;
+    else
+       address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+       calling,
+       address,                /* Protocol specific */
+       con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+       if (Con_Handle == NULL) {
+           Con_Handle = NULL;
+           free(con);
+       }
+       SMBlib_errno = -SMBlibE_CallFailed;
+       return NULL;
+
+    }
+    return (con);
+
+}
+
+/* SMB_Connect: Connect to the indicated server                       */
+/* If Con_Handle == NULL then create a handle and connect, otherwise  */
+/* use the handle passed                                              */
+
+char *SMB_Prots_Restrict[] =
+{"PC NETWORK PROGRAM 1.0",
+    NULL};
+
+
+SMB_Handle_Type
+SMB_Connect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle * tree,
+    char *service,
+    char *username,
+    char *password)
+{
+    SMB_Handle_Type con;
+    char *host, *address;
+    char temp[80], called[80], calling[80];
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+       if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return NULL;
+       }
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, service);
+    strcpy(con->username, username);
+    strcpy(con->password, password);
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;             /* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;       /* This will do for now ... */
+    con->uid = 0;              /* Until we have done a logon, no uid */
+    con->gid = getgid();
+
+    /* Now figure out the host portion of the service */
+
+    strcpy(temp, service);
+    /* AI - Added (char *) to stop compiler warnings */
+    host = (char *) strtok(temp, "/\\");       /* Separate host name portion */
+    strcpy(con->desthost, host);
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(host); i++)
+       called[i] = toupper(host[i]);
+
+    called[strlen(host)] = 0;  /* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+       calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;  /* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+       address = con->desthost;
+    else
+       address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+       calling,
+       address,                /* Protocol specific */
+       con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+       if (Con_Handle == NULL) {
+           free(con);
+           Con_Handle = NULL;
+       }
+       SMBlib_errno = -SMBlibE_CallFailed;
+       return NULL;
+
+    }
+    /* Now, negotiate the protocol */
+
+    if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
+
+       /* Hmmm what should we do here ... We have a connection, but could not
+        * negotiate ...                                                      */
+
+       return NULL;
+
+    }
+    /* Now connect to the service ... */
+
+    if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
+
+       return NULL;
+
+    }
+    return (con);
+
+}
+
+/* Logon to the server. That is, do a session setup if we can. We do not do */
+/* Unicode yet!                                                             */
+
+int
+SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len, pass_len;
+    char *p, pword[128];
+
+    /* First we need a packet etc ... but we need to know what protocol has  */
+    /* been negotiated to figure out if we can do it and what SMB format to  */
+    /* use ...                                                               */
+
+    if (Con_Handle->protocol < SMB_P_LanMan1) {
+
+       SMBlib_errno = SMBlibE_ProtLow;
+       return (SMBlibE_BAD);
+
+    }
+    strcpy(pword, PassWord);
+#ifdef PAM_SMB_ENC_PASS
+    if (Con_Handle->encrypt_passwords) {
+       pass_len = 24;
+       SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
+    } else
+#endif
+       pass_len = strlen(pword);
+
+
+    /* Now build the correct structure */
+
+    if (Con_Handle->protocol < SMB_P_NT1) {
+
+       param_len = strlen(UserName) + 1 + pass_len + 1 +
+           strlen(Con_Handle->PDomain) + 1 +
+           strlen(Con_Handle->OSName) + 1;
+
+       pkt_len = SMB_ssetpLM_len + param_len;
+
+       pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+       if (pkt == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return (SMBlibE_BAD);       /* Should handle the error */
+
+       }
+       bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
+       SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);   /* Plunk in IDF */
+       *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+       *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
+       *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
+
+       /* Now copy the param strings in with the right stuff */
+
+       p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
+
+       /* Copy  in password, then the rest. Password has a null at end */
+
+       memcpy(p, pword, pass_len);
+
+       p = p + pass_len + 1;
+
+       strcpy(p, UserName);
+       p = p + strlen(UserName);
+       *p = 0;
+
+       p = p + 1;
+
+       strcpy(p, Con_Handle->PDomain);
+       p = p + strlen(Con_Handle->PDomain);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->OSName);
+       p = p + strlen(Con_Handle->OSName);
+       *p = 0;
+
+    } else {
+
+       /* We don't admit to UNICODE support ... */
+
+       param_len = strlen(UserName) + 1 + pass_len +
+           strlen(Con_Handle->PDomain) + 1 +
+           strlen(Con_Handle->OSName) + 1 +
+           strlen(Con_Handle->LMType) + 1;
+
+       pkt_len = SMB_ssetpNTLM_len + param_len;
+
+       pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+       if (pkt == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return (-1);        /* Should handle the error */
+
+       }
+       bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
+       SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);   /* Plunk in IDF */
+       *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+       *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
+       *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
+
+       /* Now copy the param strings in with the right stuff */
+
+       p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
+
+       /* Copy  in password, then the rest. Password has no null at end */
+
+       memcpy(p, pword, pass_len);
+
+       p = p + pass_len;
+
+       strcpy(p, UserName);
+       p = p + strlen(UserName);
+       *p = 0;
+
+       p = p + 1;
+
+       strcpy(p, Con_Handle->PDomain);
+       p = p + strlen(Con_Handle->PDomain);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->OSName);
+       p = p + strlen(Con_Handle->OSName);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->LMType);
+       p = p + strlen(Con_Handle->LMType);
+       *p = 0;
+
+    }
+
+    /* Now send it and get a response */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending SessSetupX request\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_SendFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to SessSetupAndX\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_RecvFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+#ifdef DEBUG
+    fprintf(stderr, "SessSetupAndX response. Action = %i\n",
+       SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
+#endif
+
+    /* Now pick up the UID for future reference ... */
+
+    Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
+    RFCNB_Free_Pkt(pkt);
+
+    return (0);
+
+}
+
+
+/* Disconnect from the server, and disconnect all tree connects */
+
+int
+SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
+{
+
+    /* We just disconnect the connection for now ... */
+
+    RFCNB_Hangup(Con_Handle->Trans_Connect);
+
+    if (!KeepHandle)
+       free(Con_Handle);
+
+    return (0);
+
+}
diff --git a/helpers/basic_auth/MSNT/smblib.h b/helpers/basic_auth/MSNT/smblib.h
new file mode 100644 (file)
index 0000000..b08444d
--- /dev/null
@@ -0,0 +1,98 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-defines.h"
+#include "smblib-common.h"
+
+/* Just define all the entry points */
+
+/* Create a handle to allow us to set/override some parameters ...       */
+
+SMB_Handle_Type SMB_Create_Con_Handle();
+
+/* Connect to a server, but do not do a tree con etc ... */
+
+SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type, char *server, char *NTdomain);
+
+/* Connect to a server and give us back a handle. If Con == NULL, create */
+/* The handle and populate it with defaults                              */
+
+SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle * tree,
+    char *service,
+    char *username,
+    char *password);
+
+/* Negotiate a protocol                                                  */
+
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+
+/* Connect to a tree ...                                                 */
+
+void *SMB_TreeConnect(void *con_handle, void *tree_handle,
+    char *path, char *password, char *dev);
+
+/* Disconnect a tree ...                                                 */
+
+int SMB_TreeDisconect(void *tree_handle);
+
+/* Open a file                                                           */
+
+void *SMB_Open(void *tree_handle,
+    void *file_handle,
+    char *file_name,
+    unsigned short mode,
+    unsigned short search);
+
+/* Close a file                                                          */
+
+int SMB_Close(void *file_handle);
+
+/* Disconnect from server. Has flag to specify whether or not we keep the */
+/* handle.                                                                */
+
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+
+void *SMB_Create(void *Tree_Handle,
+    void *File_Handle,
+    char *file_name,
+    short search);
+
+int SMB_Delete(void *tree, char *file_name, short search);
+
+int SMB_Create_Dir(void *tree, char *dir_name);
+
+int SMB_Delete_Dir(void *tree, char *dir_name);
+
+int SMB_Check_Dir(void *tree, char *dir_name);
+
+int SMB_Get_Last_Error();
+
+int SMB_Get_Last_SMB_Err();
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+void *SMB_Logon_And_TCon(void *con, void *tree, char *user, char *pass,
+    char *service, char *st);
diff --git a/helpers/basic_auth/MSNT/std-defines.h b/helpers/basic_auth/MSNT/std-defines.h
new file mode 100644 (file)
index 0000000..c3959c6
--- /dev/null
@@ -0,0 +1,45 @@
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * SMBlib Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ */
+/* One day we will conditionalize these on OS types ... */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _STD_DEFINES_H_
+#define _STD_DEFINES_H_
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#endif /* _STD_DEFINES_H_ */
diff --git a/helpers/basic_auth/MSNT/std-includes.h b/helpers/basic_auth/MSNT/std-includes.h
new file mode 100644 (file)
index 0000000..95bc508
--- /dev/null
@@ -0,0 +1,45 @@
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * RFCNB Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ */
+/* One day we will conditionalize these on OS types ... */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Pick up define for INADDR_NONE */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
diff --git a/helpers/basic_auth/MSNT/valid.c b/helpers/basic_auth/MSNT/valid.c
new file mode 100644 (file)
index 0000000..72a9aee
--- /dev/null
@@ -0,0 +1,45 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include "smblib-priv.h"
+#include "smblib.h"
+#include "valid.h"
+
+extern int SMB_Init(void);
+extern int SMB_Logon_Server(SMB_Handle_Type, char *, char *);
+
+
+int
+Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN)
+{
+    char *SMB_Prots[] =
+    {"PC NETWORK PROGRAM 1.0",
+       "MICROSOFT NETWORKS 1.03",
+       "MICROSOFT NETWORKS 3.0",
+       "LANMAN1.0",
+       "LM1.2X002",
+       "Samba",
+       "NT LM 0.12",
+       "NT LANMAN 1.0",
+       NULL};
+    void *con;
+
+    SMB_Init();
+    con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+    if (con == NULL) {         /* Error ... */
+       con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+       if (con == NULL) {
+           return (NTV_SERVER_ERROR);
+       }
+    }
+    if (SMB_Negotiate(con, SMB_Prots) < 0) {   /* An error */
+       SMB_Discon(con, 0);
+       return (NTV_PROTOCOL_ERROR);
+    }
+    if (SMB_Logon_Server(con, USERNAME, PASSWORD) < 0) {
+       SMB_Discon(con, 0);
+       return (NTV_LOGON_ERROR);
+    }
+    SMB_Discon(con, 0);
+    return (NTV_NO_ERROR);
+}
diff --git a/helpers/basic_auth/MSNT/valid.h b/helpers/basic_auth/MSNT/valid.h
new file mode 100644 (file)
index 0000000..1d14e6b
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _VALID_H_
+#define _VALID_H_
+/* SMB User verification function */
+
+#define NTV_NO_ERROR 0
+#define NTV_SERVER_ERROR 1
+#define NTV_PROTOCOL_ERROR 2
+#define NTV_LOGON_ERROR 3
+
+int Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN);
+
+#endif
diff --git a/helpers/basic_auth/Makefile.in b/helpers/basic_auth/Makefile.in
new file mode 100644 (file)
index 0000000..b7b3fe6
--- /dev/null
@@ -0,0 +1,38 @@
+#  Makefile for storage modules in the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:43 hno Exp $
+#
+
+# The 'nop' is in the SUBDIRS list because some Unixes that can't
+# handle empty for lists.
+
+SUBDIRS                = @AUTH_BASIC_HELPERS@ nop
+
+all:
+       @for dir in $(SUBDIRS); do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) all" || exit 1; \
+           fi; \
+       done;
+
+clean:
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) clean"; \
+           fi; \
+       done
+
+distclean:
+       -rm -f Makefile
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) distclean"; \
+           fi; \
+       done
+
+.DEFAULT:
+       @for dir in $(SUBDIRS); do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+           fi; \
+       done;
diff --git a/helpers/basic_auth/NCSA/Makefile.in b/helpers/basic_auth/NCSA/Makefile.in
new file mode 100644 (file)
index 0000000..3e7c373
--- /dev/null
@@ -0,0 +1,100 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:45 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir      = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir   = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+NCSA_AUTH_EXE  = ncsa_auth$(exec_suffix)
+
+DEFAULT_PASSWD_FILE     = $(sysconfdir)/passwd
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL            = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+SNMPLIB                = @SNMPLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS           = $(NCSA_AUTH_EXE)
+OBJS           = ncsa_auth.o
+
+all:    $(NCSA_AUTH_EXE)
+
+$(OBJS): $(top_srcdir)/include/version.h
+
+$(NCSA_AUTH_EXE): ncsa_auth.o
+       $(CC) $(LDFLAGS) ncsa_auth.o -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+tags:
+       ctags *.[ch] ../include/*.h ../lib/*.[ch]
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/basic_auth/NCSA/ncsa_auth.c b/helpers/basic_auth/NCSA/ncsa_auth.c
new file mode 100644 (file)
index 0000000..ceb8157
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * ncsa_auth.c
+ *
+ * AUTHOR: Arjan de Vet <Arjan.deVet@adv.iae.nl>
+ *
+ * Example authentication program for Squid, based on the original
+ * proxy_auth code from client_side.c, written by
+ * Jon Thackray <jrmt@uk.gdscorp.com>.
+ *
+ * Uses a NCSA httpd style password file for authentication with the
+ * following improvements suggested by various people:
+ *
+ * - comment lines are possible and should start with a '#';
+ * - empty or blank lines are possible;
+ * - extra fields in the password file are ignored; this makes it
+ *   possible to use a Unix password file but I do not recommend that.
+ *
+ */
+
+#include "config.h"
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "util.h"
+#include "hash.h"
+
+static hash_table *hash = NULL;
+static HASHFREE my_free;
+
+typedef struct _user_data {
+    /* first two items must be same as hash_link */
+    char *user;
+    struct _user_data *next;
+    char *passwd;
+} user_data;
+
+static void
+my_free(void *p)
+{
+    user_data *u = p;
+    xfree(u->user);
+    xfree(u->passwd);
+    xfree(u);
+}
+
+static void
+read_passwd_file(const char *passwdfile)
+{
+    FILE *f;
+    char buf[8192];
+    user_data *u;
+    char *user;
+    char *passwd;
+    if (hash != NULL) {
+       hashFreeItems(hash, my_free);
+    }
+    /* initial setup */
+    hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+    if (NULL == hash) {
+       fprintf(stderr, "ncsa_auth: cannot create hash table\n");
+       exit(1);
+    }
+    f = fopen(passwdfile, "r");
+    while (fgets(buf, 8192, f) != NULL) {
+       if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
+           (buf[0] == '\n'))
+           continue;
+       user = strtok(buf, ":\n");
+       passwd = strtok(NULL, ":\n");
+       if ((strlen(user) > 0) && passwd) {
+           u = xmalloc(sizeof(*u));
+           u->user = xstrdup(user);
+           u->passwd = xstrdup(passwd);
+           hash_join(hash, (hash_link *) u);
+       }
+    }
+    fclose(f);
+}
+
+int
+main(int argc, char **argv)
+{
+    struct stat sb;
+    time_t change_time = 0;
+    char buf[256];
+    char *user, *passwd, *p;
+    user_data *u;
+    setbuf(stdout, NULL);
+    if (argc != 2) {
+       fprintf(stderr, "Usage: ncsa_auth <passwordfile>\n");
+       exit(1);
+    }
+    if (stat(argv[1], &sb) != 0) {
+       fprintf(stderr, "cannot stat %s\n", argv[1]);
+       exit(1);
+    }
+    while (fgets(buf, 256, stdin) != NULL) {
+       if ((p = strchr(buf, '\n')) != NULL)
+           *p = '\0';          /* strip \n */
+       if (stat(argv[1], &sb) == 0) {
+           if (sb.st_mtime != change_time) {
+               read_passwd_file(argv[1]);
+               change_time = sb.st_mtime;
+           }
+       }
+       if ((user = strtok(buf, " ")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       if ((passwd = strtok(NULL, "")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       u = hash_lookup(hash, user);
+       if (u == NULL) {
+           printf("ERR\n");
+       } else if (strcmp(u->passwd, (char *) crypt(passwd, u->passwd))) {
+           printf("ERR\n");
+       } else {
+           printf("OK\n");
+       }
+    }
+    exit(0);
+}
diff --git a/helpers/basic_auth/PAM/Makefile.in b/helpers/basic_auth/PAM/Makefile.in
new file mode 100644 (file)
index 0000000..f8a8c74
--- /dev/null
@@ -0,0 +1,96 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:45 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir      = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir   = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+PAM_AUTH_EXE   = pam_auth$(exec_suffix)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL            = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+SNMPLIB                = @SNMPLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@ @DLLIB@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+DEFINES                = 
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -lpam $(XTRA_LIBS)
+
+LIBPROGS        = $(PAM_AUTH_EXE)
+OBJS           = pam_auth.o
+
+all:    $(PAM_AUTH_EXE)
+
+$(PAM_AUTH_EXE): pam_auth.o
+       $(CC) $(LDFLAGS) pam_auth.o -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(libexecdir); then \
+               echo "mkdir $(libexecdir)"; \
+               mkdir $(libexecdir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(LIBPROGS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(libexecdir); \
+               $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) -f $(libexecdir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(LIBPROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+tags:
+       ctags *.[ch]
+
+depend:
+       $(MAKEDEPEND) -fMakefile *.c
diff --git a/helpers/basic_auth/PAM/pam_auth.c b/helpers/basic_auth/PAM/pam_auth.c
new file mode 100644 (file)
index 0000000..36c03b2
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * $Id: pam_auth.c,v 1.1 2001/01/07 23:36:45 hno Exp $
+ *
+ * PAM authenticator module for Squid.
+ * Copyright (C) 1999 Henrik Nordstrom <hno@hem.passagen.se>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Install instructions:
+ *
+ * This program authenticates users against a PAM configured authentication
+ * service "squid". This allows you to authenticate Squid users to any
+ * authentication source for which you have a PAM module. Commonly available
+ * PAM modules includes "UNIX", RADIUS, Kerberos and SMB, but a lot of other
+ * PAM modules are available from various sources.
+ *
+ * Example PAM configuration for standard UNIX passwd authentication:
+ * /etc/pam.conf:
+ *  squid auth     required /lib/security/pam_unix.so.1
+ *  squid account  required /lib/security/pam_unix.so.1
+ *
+ * Note that some PAM modules (for example shadow password authentication)
+ * requires the program to be installed suid root, or PAM will not allow
+ * it to authenticate other users than it runs as (this is a security
+ * limitation of PAM to avoid automated probing of passwords).
+ *
+ * Compile this program with: gcc -o pam_auth pam_auth.c -lpam -ldl
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+
+#include <security/pam_appl.h>
+
+#define BUFSIZE 8192
+
+
+/* The default PAM service name */
+#ifndef SQUID_PAM_SERVICE
+#define SQUID_PAM_SERVICE "squid"
+#endif
+
+/* How often to reinitialize PAM, in seconds. Undefined = never, 0=always */
+/* #define PAM_CONNECTION_TTL 60 */
+
+static int reset_pam = 1;      /* Set to one if it is time to reset PAM processing */
+
+static char *password = NULL;  /* Workaround for Solaris 2.6 brokenness */
+
+/*
+ * A simple "conversation" function returning the supplied password.
+ * Has a bit to much error control, but this is my first PAM application
+ * so I'd rather check everything than make any mistakes. The function
+ * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
+ */
+static int
+password_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
+{
+    if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
+       fprintf(stderr, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
+       return PAM_CONV_ERR;
+    }
+    if (!appdata_ptr) {
+       /* Workaround for Solaris 2.6 where the PAM library is broken
+        * and does not pass appdata_ptr to the conversation routine
+        */
+       appdata_ptr = password;
+    }
+    if (!appdata_ptr) {
+       fprintf(stderr, "ERROR: No password available to password_converstation!\n");
+       return PAM_CONV_ERR;
+    }
+    *resp = calloc(num_msg, sizeof(struct pam_response));
+    if (!*resp) {
+       fprintf(stderr, "ERROR: Out of memory!\n");
+       return PAM_CONV_ERR;
+    }
+    (*resp)[0].resp = strdup((char *) appdata_ptr);
+    (*resp)[0].resp_retcode = 0;
+
+    return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
+}
+
+static struct pam_conv conv =
+{
+    &password_conversation,
+    NULL
+};
+
+void
+signal_received(int sig)
+{
+    reset_pam = 1;
+    signal(sig, signal_received);
+}
+
+int
+main(int argc, char *argv[])
+{
+    pam_handle_t *pamh = NULL;
+    int retval;
+    char *user;
+    /* char *password; */
+    char buf[BUFSIZE];
+    time_t pamh_created = 0;
+
+    signal(SIGHUP, signal_received);
+
+    /* make standard output line buffered */
+    setvbuf(stdout, NULL, _IOLBF, 0);
+
+    while (retval = PAM_SUCCESS, fgets(buf, BUFSIZE, stdin)) {
+       user = buf;
+       password = strchr(buf, '\n');
+       if (!password) {
+           fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
+           fprintf(stdout, "ERR\n");
+           continue;
+       }
+       *password = '\0';
+       password = strchr(buf, ' ');
+       if (!password) {
+           fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
+           fprintf(stdout, "ERR\n");
+           continue;
+       }
+       *password++ = '\0';
+       conv.appdata_ptr = (char *) password;   /* from buf above. not allocated */
+#ifdef PAM_CONNECTION_TTL
+       if (pamh_created + PAM_CONNECTION_TTL >= time(NULL))
+           reset_pam = 1;
+#endif
+       if (reset_pam && pamh) {
+           /* Close previous PAM connection */
+           retval = pam_end(pamh, retval);
+           if (retval != PAM_SUCCESS) {
+               fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
+           }
+           pamh = NULL;
+       }
+       if (!pamh) {
+           /* Initialize PAM connection */
+           retval = pam_start(SQUID_PAM_SERVICE, "squid@", &conv, &pamh);
+           if (retval != PAM_SUCCESS) {
+               fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
+           }
+           reset_pam = 0;
+           pamh_created = time(NULL);
+       }
+       if (retval == PAM_SUCCESS)
+           retval = pam_set_item(pamh, PAM_USER, user);
+       if (retval == PAM_SUCCESS)
+           retval = pam_set_item(pamh, PAM_CONV, &conv);
+       if (retval == PAM_SUCCESS)
+           retval = pam_authenticate(pamh, 0);
+       if (retval == PAM_SUCCESS)
+           retval = pam_acct_mgmt(pamh, 0);
+       if (retval == PAM_SUCCESS) {
+           fprintf(stdout, "OK\n");
+       } else {
+           fprintf(stdout, "ERR\n");
+       }
+    }
+
+    if (pamh) {
+       retval = pam_end(pamh, retval);
+       if (retval != PAM_SUCCESS) {
+           pamh = NULL;
+           fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
+       }
+    }
+    return (retval == PAM_SUCCESS ? 0 : 1);    /* indicate success */
+}
diff --git a/helpers/basic_auth/SMB/COPYING-2.0 b/helpers/basic_auth/SMB/COPYING-2.0
new file mode 100644 (file)
index 0000000..d684351
--- /dev/null
@@ -0,0 +1,341 @@
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+        Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/helpers/basic_auth/SMB/Makefile.in b/helpers/basic_auth/SMB/Makefile.in
new file mode 100644 (file)
index 0000000..8227978
--- /dev/null
@@ -0,0 +1,118 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:46 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+# SAMBAPREFIX must point to the directory where Samba has been installed.
+# By default, Samba is installed in /usr/local/samba. If you changed this
+# by using the --prefix option when configuring Samba, you need to change
+# SAMBAPREFIX accordingly.
+
+SAMBAPREFIX=/usr/local/samba
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir      = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir   = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+SMB_AUTH_EXE   = smb_auth$(exec_suffix)
+SMB_AUTH_HELPER        = smb_auth.sh
+SMB_AUTH_HELPER_PATH = $(libexecdir)/$(SMB_AUTH_HELPER)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL            = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+SNMPLIB                = @SNMPLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+DEFINES                = -DSAMBAPREFIX=\"$(SAMBAPREFIX)\" -DHELPERSCRIPT=\"$(SMB_AUTH_HELPER_PATH)\"
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = $(XTRA_LIBS)
+
+LIBPROGS        = $(SMB_AUTH_EXE)
+LIBSCRIPTS     = $(SMB_AUTH_HELPER)
+OBJS           = smb_auth.o
+
+all:    $(LIBPROGS)
+
+$(SMB_AUTH_EXE): smb_auth.o
+       $(CC) $(LDFLAGS) smb_auth.o -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(libexecdir); then \
+               echo "mkdir $(libexecdir)"; \
+               mkdir $(libexecdir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(LIBPROGS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(libexecdir); \
+               $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) -f $(libexecdir)/-$$f; \
+               fi; \
+       done
+       @for f in $(LIBSCRIPTS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(libexecdir); \
+               $(INSTALL_BIN) $(srcdir)/$$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) -f $(libexecdir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(LIBPROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+tags:
+       ctags *.[ch]
+
+depend:
+       $(MAKEDEPEND) -fMakefile *.c
diff --git a/helpers/basic_auth/SMB/README b/helpers/basic_auth/SMB/README
new file mode 100644 (file)
index 0000000..f550dc3
--- /dev/null
@@ -0,0 +1,3 @@
+For documentation, please refer to
+
+       http://www.hacom.nl/~richard/software/smb_auth.html
diff --git a/helpers/basic_auth/SMB/smb_auth.c b/helpers/basic_auth/SMB/smb_auth.c
new file mode 100644 (file)
index 0000000..5a5ef10
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ *  smb_auth - SMB proxy authentication module
+ *  Copyright (C) 1998  Richard Huveneers <richard@hekkihek.hacom.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFSIZE                        256
+#define NMB_UNICAST            1
+#define NMB_BROADCAST  2
+
+struct SMBDOMAIN {
+    char *name;                        /* domain name */
+    char *sname;               /* match this with user input */
+    char *passthrough;         /* pass-through authentication */
+    char *nmbaddr;             /* name service address */
+    int nmbcast;               /* broadcast or unicast */
+    char *authshare;           /* share name of auth file */
+    char *authfile;            /* pathname of auth file */
+    struct SMBDOMAIN *next;    /* linked list */
+};
+
+struct SMBDOMAIN *firstdom = NULL;
+struct SMBDOMAIN *lastdom = NULL;
+
+/*
+ * escape the backslash character, since it has a special meaning
+ * to the read command of the bourne shell.
+ */
+
+void
+print_esc(FILE * p, char *s)
+{
+    char buf[256];
+    char *t;
+    int i = 0;
+
+    for (t = s; *t != '\0'; t++) {
+       if (i > 250) {
+           buf[i] = '\0';
+           (void) fputs(buf, p);
+           i = 0;
+       }
+       if (*t == '\\')
+           buf[i++] = '\\';
+
+       buf[i++] = *t;
+    }
+
+    if (i > 0) {
+       buf[i] = '\0';
+       (void) fputs(buf, p);
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+    int i;
+    char buf[BUFSIZE];
+    struct SMBDOMAIN *dom;
+    char *s;
+    char *user;
+    char *pass;
+    char *domname;
+    FILE *p;
+    int debug = 0;
+    char *shcmd;
+
+    /* make standard output line buffered */
+    if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
+       return 1;
+
+    /* parse command line arguments */
+    for (i = 1; i < argc; i++) {
+       if (strcmp(argv[i], "-d") == 0) {
+           debug = 1;
+           continue;
+       }
+       /* the next options require an argument */
+       if (i + 1 == argc)
+           break;
+
+       if (strcmp(argv[i], "-W") == 0) {
+           if ((dom = (struct SMBDOMAIN *) malloc(sizeof(struct SMBDOMAIN))) == NULL)
+                         return 1;
+
+           dom->name = dom->sname = argv[++i];
+           dom->passthrough = "";
+           dom->nmbaddr = "";
+           dom->nmbcast = NMB_BROADCAST;
+           dom->authshare = "NETLOGON";
+           dom->authfile = "proxyauth";
+           dom->next = NULL;
+
+           /* append to linked list */
+           if (lastdom != NULL)
+               lastdom->next = dom;
+           else
+               firstdom = dom;
+
+           lastdom = dom;
+           continue;
+       }
+       if (strcmp(argv[i], "-w") == 0) {
+           if (lastdom != NULL)
+               lastdom->sname = argv[++i];
+           continue;
+       }
+       if (strcmp(argv[i], "-P") == 0) {
+           if (lastdom != NULL)
+               lastdom->passthrough = argv[++i];
+           continue;
+       }
+       if (strcmp(argv[i], "-B") == 0) {
+           if (lastdom != NULL) {
+               lastdom->nmbaddr = argv[++i];
+               lastdom->nmbcast = NMB_BROADCAST;
+           }
+           continue;
+       }
+       if (strcmp(argv[i], "-U") == 0) {
+           if (lastdom != NULL) {
+               lastdom->nmbaddr = argv[++i];
+               lastdom->nmbcast = NMB_UNICAST;
+           }
+           continue;
+       }
+       if (strcmp(argv[i], "-S") == 0) {
+           if (lastdom != NULL) {
+               if ((lastdom->authshare = strdup(argv[++i])) == NULL)
+                   return 1;
+
+               /* convert backslashes to forward slashes */
+               for (s = lastdom->authshare; *s != '\0'; s++)
+                   if (*s == '\\')
+                       *s = '/';
+
+               /* strip leading forward slash from share name */
+               if (*lastdom->authshare == '/')
+                   lastdom->authshare++;
+
+               if ((s = strchr(lastdom->authshare, '/')) != NULL) {
+                   *s = '\0';
+                   lastdom->authfile = s + 1;
+               }
+           }
+           continue;
+       }
+    }
+
+    shcmd = debug ? HELPERSCRIPT : HELPERSCRIPT " > /dev/null 2>&1";
+
+    /* pass to helper script */
+    if (putenv("SAMBAPREFIX=" SAMBAPREFIX) != 0)
+       return 1;
+
+    while (1) {
+       if (fgets(buf, BUFSIZE, stdin) == NULL)
+           break;
+
+       if ((s = strchr(buf, '\n')) == NULL)
+           continue;
+       *s = '\0';
+
+       if ((s = strchr(buf, ' ')) == NULL) {
+           (void) printf("ERR\n");
+           continue;
+       }
+       *s = '\0';
+
+       user = buf;
+       pass = s + 1;
+       domname = NULL;
+
+       if ((s = strchr(user, '\\')) != NULL) {
+           *s = '\0';
+           domname = user;
+           user = s + 1;
+       }
+       /* match domname with linked list */
+       if (domname != NULL && strlen(domname) > 0) {
+           for (dom = firstdom; dom != NULL; dom = dom->next)
+               if (strcasecmp(dom->sname, domname) == 0)
+                   break;
+       } else
+           dom = firstdom;
+
+       if (dom == NULL) {
+           (void) printf("ERR\n");
+           continue;
+       }
+       if ((p = popen(shcmd, "w")) == NULL) {
+           (void) printf("ERR\n");
+           continue;
+       }
+       (void) fprintf(p, "%s\n", dom->name);
+       (void) fprintf(p, "%s\n", dom->passthrough);
+       (void) fprintf(p, "%s\n", dom->nmbaddr);
+       (void) fprintf(p, "%d\n", dom->nmbcast);
+       (void) fprintf(p, "%s\n", dom->authshare);
+       (void) fprintf(p, "%s\n", dom->authfile);
+       (void) fprintf(p, "%s\n", user);
+       /* the password can contain special characters */
+       print_esc(p, pass);
+       (void) fputc('\n', p);
+       (void) fflush(p);
+
+       if (pclose(p) == 0)
+           (void) printf("OK\n");
+       else
+           (void) printf("ERR\n");
+
+    }                          /* while (1) */
+    return 0;
+}
diff --git a/helpers/basic_auth/SMB/smb_auth.sh b/helpers/basic_auth/SMB/smb_auth.sh
new file mode 100644 (file)
index 0000000..99f8615
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+#
+# smb_auth - SMB proxy authentication module
+# Copyright (C) 1998  Richard Huveneers <richard@hekkihek.hacom.nl>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+read DOMAINNAME
+read PASSTHROUGH
+read NMBADDR
+read NMBCAST
+read AUTHSHARE
+read AUTHFILE
+read SMBUSER
+read SMBPASS
+
+# Find domain controller
+echo "Domain name: $DOMAINNAME"
+if [ -n "$PASSTHROUGH" ]
+then
+  echo "Pass-through authentication: yes: $PASSTHROUGH"
+else
+  echo "Pass-through authentication: no"
+  PASSTHROUGH="$DOMAINNAME"
+fi
+if [ -n "$NMBADDR" ]
+then
+  if [ "$NMBCAST" = "1" ]
+  then
+    addropt="-U $NMBADDR -R"
+  else
+    addropt="-B $NMBADDR"
+  fi
+else
+  addropt=""
+fi
+echo "Query address options: $addropt"
+dcip=`$SAMBAPREFIX/bin/nmblookup $addropt "$PASSTHROUGH#1c" | awk '/^[0-9.]+ / { print $1 ; exit }'`
+echo "Domain controller IP address: $dcip"
+[ -n "$dcip" ] || exit 1
+
+# All right, we have the IP address of a domain controller,
+# but we need its name too
+dcname=`$SAMBAPREFIX/bin/nmblookup -A $dcip | awk '$2 == "<00>" { print $1 ; exit }'`
+echo "Domain controller NETBIOS name: $dcname"
+[ -n "$dcname" ] || exit 1
+
+# Pass password to smbclient through environment. Not really safe.
+USER="$SMBUSER%$SMBPASS"
+export USER
+
+# Read the contents of the file $AUTHFILE on the $AUTHSHARE share
+authfilebs=`echo "$AUTHFILE" | tr / '\\\\'`
+authinfo=`$SAMBAPREFIX/bin/smbclient "//$dcname/$AUTHSHARE" -I $dcip -d 0 -E -W "$DOMAINNAME" -c "get $authfilebs -" 2>/dev/null`
+echo "Contents of //$dcname/$AUTHSHARE/$AUTHFILE: $authinfo"
+
+# Allow for both \n and \r\n end-of-line termination
+[ "$authinfo" = "allow" -o "$authinfo" = "allow\r" ] || exit 1
+exit 0
diff --git a/helpers/basic_auth/YP/Makefile.in b/helpers/basic_auth/YP/Makefile.in
new file mode 100644 (file)
index 0000000..bdb3d7e
--- /dev/null
@@ -0,0 +1,100 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:46 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+cgi_suffix     = @cgi_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+libexecdir      = @libexecdir@
+sysconfdir     = @sysconfdir@
+localstatedir   = @localstatedir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+YP_AUTH_EXE    = yp_auth$(exec_suffix)
+
+DEFAULT_PASSWD_FILE     = $(sysconfdir)/passwd
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+INSTALL_FILE   = @INSTALL_DATA@
+INSTALL_SUID   = @INSTALL_PROGRAM@ -o root -m 4755
+RANLIB         = @RANLIB@
+LN_S           = @LN_S@
+PERL            = @PERL@
+CRYPTLIB       = @CRYPTLIB@
+REGEXLIB       = @REGEXLIB@
+PTHREADLIB     = @PTHREADLIB@
+SNMPLIB                = @SNMPLIB@
+MALLOCLIB      = @LIB_MALLOC@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS           = $(YP_AUTH_EXE)
+OBJS           = yp_auth.o nis_support.o
+
+all:    $(YP_AUTH_EXE)
+
+$(OBJS): $(top_srcdir)/include/version.h
+
+$(YP_AUTH_EXE): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+# Michael Lupp <mike@nemesis.saar.de> wants to know about additions
+# to the install target.
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+tags:
+       ctags *.[ch] ../include/*.h ../lib/*.[ch]
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/basic_auth/YP/nis_support.c b/helpers/basic_auth/YP/nis_support.c
new file mode 100644 (file)
index 0000000..48a82c0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Written By Rabellino Sergio (rabellino@di.unito.it) For Solaris 2.x
+ */
+
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+
+#define NO_YPERR 0             /* There is no error */
+
+int
+get_nis_password(char *user, char *passwd, char *nisdomain, char *nismap)
+{
+    char *val = NULL;
+    char *username = NULL;
+    int vallen, res;
+
+#ifdef DEBUG
+    printf("Domain is set to %s\n", nisdomain);
+    printf("YP Map is set to %s\n", nismap);
+#endif
+
+    /* Get NIS entry */
+    res = yp_match(nisdomain, nismap, user, strlen(user), &val, &vallen);
+
+    switch (res) {
+    case NO_YPERR:
+       username = strtok(val, ":");
+       strcpy(passwd, strtok(NULL, ":"));
+       free(val);
+       break;
+    case YPERR_YPBIND:
+       syslog(LOG_ERR, "Squid Authentication through ypbind failure: can't communicate with ypbind");
+       return 1;
+    case YPERR_KEY:            /* No such key in map */
+       return 1;
+    default:
+       return 1;
+    }
+    return 0;
+}
diff --git a/helpers/basic_auth/YP/yp_auth.c b/helpers/basic_auth/YP/yp_auth.c
new file mode 100644 (file)
index 0000000..2b54e05
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Adapted By Rabellino Sergio (rabellino@di.unito.it) For Solaris 2.x
+ * From NCSA Authentication module
+ */
+
+#include "config.h"
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "util.h"
+#include "hash.h"
+
+int get_nis_password();
+
+
+int
+main(int argc, char **argv)
+{
+    char buf[256];
+    char nispasswd[15];
+    char *nisdomain;
+    char *nismap;
+    char *user, *passwd, *p;
+    int res;
+    setbuf(stdout, NULL);
+
+    if (argc != 3) {
+       fprintf(stderr, "Usage: yp_auth <domainname> <nis map for password>\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Example yp_auth mydomain.com passwd.byname\n");
+       exit(1);
+    }
+    nisdomain = argv[1];
+    nismap = argv[2];
+
+    while (fgets(buf, 256, stdin) != NULL) {
+       if ((p = strchr(buf, '\n')) != NULL)
+           *p = '\0';          /* strip \n */
+
+       if ((user = strtok(buf, " ")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       if ((passwd = strtok(NULL, "")) == NULL) {
+           printf("ERR\n");
+           continue;
+       }
+       res = get_nis_password(user, nispasswd, nisdomain, nismap);
+
+       if (res) {
+           /* User does not exist */
+           printf("ERR\n");
+       } else if (strcmp(nispasswd, (char *) crypt(passwd, nispasswd))) {
+           /* Password incorrect */
+           printf("ERR\n");
+       } else {
+           /* All ok !, thanks... */
+           printf("OK\n");
+       }
+    }
+    exit(0);
+}
diff --git a/helpers/basic_auth/getpwnam/Makefile.in b/helpers/basic_auth/getpwnam/Makefile.in
new file mode 100644 (file)
index 0000000..5345559
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:47 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+GETPWNAM_AUTH_EXE      = getpwnam_auth$(exec_suffix)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+CRYPTLIB       = @CRYPTLIB@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS          = $(GETPWNAM_AUTH_EXE)
+OBJS           = getpwnam_auth.o
+
+all:    $(GETPWNAM_AUTH_EXE)
+
+$(OBJS): $(top_srcdir)/include/version.h
+
+$(GETPWNAM_AUTH_EXE): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/basic_auth/getpwnam/getpwnam_auth.c b/helpers/basic_auth/getpwnam/getpwnam_auth.c
new file mode 100644 (file)
index 0000000..e71c365
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * getpwnam_auth.c
+ *
+ * AUTHOR: Erik Hofman <erik.hofman@a1.nl>
+ *         Robin Elfrink <robin@a1.nl>
+ *
+ * Example authentication program for Squid, based on the
+ * original proxy_auth code from client_side.c, written by
+ * Jon Thackray <jrmt@uk.gdscorp.com>.
+ *
+ * Uses getpwnam() routines for authentication.
+ * This has the following advantages over the NCSA module:
+ * 
+ * - Allow authentication of all know local users
+ * - Allows authentication through nsswitch.conf
+ *   + can handle NIS(+) requests
+ *   + can handle LDAP request
+ *   + can handle PAM request
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+
+#define ERR    "ERR\n"
+#define OK     "OK\n"
+
+int
+main()
+{
+    char buf[256];
+    struct passwd *pwd;
+    char *user, *passwd, *p;
+
+    setbuf(stdout, NULL);
+    while (fgets(buf, 256, stdin) != NULL) {
+
+       if ((p = strchr(buf, '\n')) != NULL)
+           *p = '\0';          /* strip \n */
+
+       if ((user = strtok(buf, " ")) == NULL) {
+           printf(ERR);
+           continue;
+       }
+       if ((passwd = strtok(NULL, "")) == NULL) {
+           printf(ERR);
+           continue;
+       }
+       pwd = getpwnam(user);
+       if (pwd == NULL) {
+           printf(ERR);
+       } else {
+           if (strcmp(pwd->pw_passwd, (char *) crypt(passwd, pwd->pw_passwd))) {
+               printf(ERR);
+           } else {
+               printf(OK);
+           }
+       }
+    }
+    exit(0);
+}
diff --git a/helpers/basic_auth/multi-domain-NTLM/README.txt b/helpers/basic_auth/multi-domain-NTLM/README.txt
new file mode 100644 (file)
index 0000000..5ea1f40
--- /dev/null
@@ -0,0 +1,17 @@
+
+From: "Chemolli Francesco (USI)" <ChemolliF@GruppoCredit.it>
+Subject: Multiple NT domains authenticator
+Date: Fri, 7 Jul 2000 15:37:32 +0200 
+
+This is the multi-domain NTLM authenticator, blissfully undocumented
+(but there's a few strategic comments, so that at least the user
+is not left alone).
+
+The user is expected to enter his/her credentials as domain\username
+or domain/username (in analogy to what M$-Proxy does).
+
+Requires Authen::SMB from CPAN and Samba if you need to perform netbios
+queries.
+
+        Francesco 'Kinkie' Chemolli
+
diff --git a/helpers/basic_auth/multi-domain-NTLM/smb_auth.pl b/helpers/basic_auth/multi-domain-NTLM/smb_auth.pl
new file mode 100644 (file)
index 0000000..34972a7
--- /dev/null
@@ -0,0 +1,132 @@
+#!/usr/bin/perl
+
+#if you define this, debugging output will be printed to STDERR.
+$debug=1;
+
+#to force using some DC for some domains, fill in this hash.
+#the key is a regexp matched against the domain name
+# the value is an array ref with PDC and BDC.
+# the order the names are matched in is UNDEFINED.
+#i.e.:
+# %controllers = ( "domain" => ["pdc","bdc"]);
+
+#%controllers = ( ".*" => ["tlc5",undef]);
+
+#define this if you wish to use a WINS server. If undefined, broadcast
+# will be attempted.
+$wins_server="c0wins";
+
+
+# Some servers (at least mine) really really want to be called by address.
+# If this variable is defined, we'll ask nmblookup to do a reverse DNS on the
+#  DC addresses. It might fail though, for instance because you have a crappy
+#  DNS with no reverse zones or records. If it doesn't work, you'll have to
+#  fall back to the %controllers hack.
+$try_reverse_dns=1;
+
+# Soem servers (at least mine) don't like to be called by their fully
+#  qualified name. define this if you wish to call them ONLY by their
+#  hostname.
+$dont_use_fqdn=1;
+
+#no more user-serviceable parts
+use Authen::Smb;
+
+#variables: 
+# %pdc used to cache the domain -> pdc_ip values. IT NEVER EXPIRES!
+
+
+while (<>) {
+       if (! m;([^\\]+)(\\|/)(\S+)\s(.*); ) { #parse the line
+               print "ERR\n";
+               next;
+       }
+       $domain=$1;
+       $user=$3;
+       $pass=$4;
+       print STDERR "domain: $domain, user: $user, pass=$pass\n" 
+               if (defined ($debug));
+       # check out that we know the PDC address
+       if (!$pdc{$domain}) {
+    ($pdc,$bdc)=&discover_dc($domain);
+    if ($pdc) {
+      $pdc{$domain}=$pdc;
+      $bdc{$domain}=$bdc;
+    }
+       }
+       $pdc=$pdc{$domain};
+       $bdc=$bdc{$domain};
+       if (!$pdc) {
+               #a pdc was not found
+               print "ERR\n";
+               print STDERR "No PDC found\n" if (defined($debug));
+               next;
+       }
+
+  print STDERR "querying '$pdc' and '$bdc' for user '$domain\\$user', ".
+    "pass $pass\n" if (defined($debug));
+  $result=Authen::Smb::authen($user,$pass,$pdc,$bdc,$domain);
+  print STDERR "result is: $nt_results{$result} ($result)\n"
+    if (defined($debug));
+  if ($result == NTV_NO_ERROR) {
+    print STDERR ("OK for user '$domain\\$user'\n") if (defined($debug));
+    print ("OK\n");
+  } else {
+    print STDERR "Could not authenticate user '$domain\\$user'\n";
+    print ("ERR\n");
+  }
+}
+
+#why do Microsoft servers have to be so damn picky and convoluted?
+sub discover_dc {
+  my $domain = shift @_;
+  my ($pdc, $bdc, $lookupstring, $datum);
+
+  foreach (keys %controllers) {
+    if ($domain =~ /$_/) {
+      print STDERR "DCs forced by user: $_ => ".
+        join(',',@{$controllers{$_}}).
+        "\n" if (defined($debug));
+      return @{$controllers{$_}};
+    }
+  }
+  $lookupstring="nmblookup";
+  $lookupstring.=" -R -U $wins_server" if (defined($wins_server));
+  $lookupstring.=" -T" if (defined($try_reverse_dns));
+  $lookupstring.=" '$domain#1c'";
+  print STDERR "Discovering PDC: $lookupstring\n"
+    if (defined($debug));
+  #discover the PDC address
+  open(PDC,"$lookupstring|");
+  while (<PDC>) {
+    print STDERR "response line: $_" if (defined($debug));
+    if (m|(.*), (\d+\.\d+\.\d+\.\d+)|) {
+      $datum=$1;
+      print STDERR "matched $datum\n" if (defined($debug));
+      if (defined($dont_use_fqdn) && $datum =~ /^([^.]+)\..*/) {
+        $datum=$1;
+        print STDERR "stripped domain name: $datum\n" if (defined($debug));
+      }
+    } elsif (m|^(\d+\.\d+\.\d+\.\d+)|) {
+      $datum=$1;
+    } else {
+      #no data here, go to next line
+      next;
+    }
+    if ($datum) {
+      if ($pdc) {
+        $bdc=$datum;
+        print STDERR "BDC is $datum\n" if (defined($debug));
+        last;
+      }        else {
+        $pdc=$datum;
+        print STDERR "PDC is $datum\n" if (defined($debug));
+      }
+      last;
+    }
+  }
+  close(PDC);
+  return ($pdc,$bdc) if ($pdc);
+  return 0;
+}
+
diff --git a/helpers/ntlm_auth/Makefile.in b/helpers/ntlm_auth/Makefile.in
new file mode 100644 (file)
index 0000000..0520eeb
--- /dev/null
@@ -0,0 +1,38 @@
+#  Makefile for storage modules in the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:48 hno Exp $
+#
+
+# The 'nop' is in the SUBDIRS list because some Unixes that can't
+# handle empty for lists.
+
+SUBDIRS                = @NTLM_AUTH_HELPERS@ nop
+
+all:
+       @for dir in $(SUBDIRS); do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) all" || exit 1; \
+           fi; \
+       done;
+
+clean:
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) clean"; \
+           fi; \
+       done
+
+distclean:
+       -rm -f Makefile
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) distclean"; \
+           fi; \
+       done
+
+.DEFAULT:
+       @for dir in $(SUBDIRS); do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+           fi; \
+       done;
diff --git a/helpers/ntlm_auth/SMB/Makefile.in b/helpers/ntlm_auth/SMB/Makefile.in
new file mode 100644 (file)
index 0000000..6382f47
--- /dev/null
@@ -0,0 +1,86 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:48 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+NTLM_AUTH_EXE  = ntlm_auth$(exec_suffix)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+CRYPTLIB       = @CRYPTLIB@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(srcdir)/smbval -I$(top_srcdir)/include
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lntlmauth -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS          = $(NTLM_AUTH_EXE)
+OBJS           = ntlm_auth.o libntlmssp.o
+
+all:   $(NTLM_AUTH_EXE)  smbval/smbvalid.a
+
+$(OBJS): $(top_srcdir)/include/version.h ntlm.h
+
+$(NTLM_AUTH_EXE): $(OBJS) smbval/smbvalid.a 
+       $(CC) $(LDFLAGS) $(OBJS) smbval/smbvalid.a -o $@ $(AUTH_LIBS)
+
+smbval/smbvalid.a: smbval/stamp
+
+smbval smbval/stamp:
+       @sh -c "cd smbval && $(MAKE) all"
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean:
+       -rm -rf *.o *pure_* core $(PROGS)
+       cd smbval; make clean
+
+distclean:     clean
+       -rm -f Makefile
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/ntlm_auth/SMB/libntlmssp.c b/helpers/ntlm_auth/SMB/libntlmssp.c
new file mode 100644 (file)
index 0000000..6c9ef08
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+
+#include "ntlm.h"
+#include "util.h"              /* from Squid */
+#include "valid.h"
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "smblib-priv.h"       /* for SMB_Handle_Type */
+
+/* a few forward-declarations. Hackish, but I don't care right now */
+SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+    char *server, char *NTdomain);
+
+/* this one is reallllly haackiish. We really should be using anything from smblib-priv.h
+ */
+static char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL};
+
+#if 0
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord, char *Domain, int precrypted);
+#endif
+
+#ifdef DEBUG
+#define debug_dump_ntlmssp_flags dump_ntlmssp_flags
+#else /* DEBUG */
+#define debug_dump_ntlmssp_flags(X)    /* empty */
+#endif /* DEBUG */
+
+
+static char challenge[NONCE_LEN];
+SMB_Handle_Type handle = NULL;
+
+/* Disconnects from the DC. A reconnection will be done upon the next request
+ */
+void
+dc_disconnect()
+{
+    if (handle != NULL)
+       SMB_Discon(handle, 0);
+    handle = NULL;
+}
+
+int
+connectedp()
+{
+    return (handle != NULL);
+}
+
+
+/* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
+int
+is_dc_ok(char *domain,
+    char *domain_controller)
+{
+    SMB_Handle_Type h = SMB_Connect_Server(NULL, domain_controller, domain);
+    if (h == NULL)
+       return 0;
+    SMB_Discon(h, 0);
+    return 1;
+}
+
+
+/* returns 0 on success, > 0 on failure */
+static int
+init_challenge(char *domain, char *domain_controller)
+{
+    int smberr;
+    char errstr[100];
+
+    if (handle != NULL) {
+       return 0;
+    }
+    debug("Connecting to server %s domain %s\n", domain_controller, domain);
+    handle = SMB_Connect_Server(NULL, domain_controller, domain);
+    smberr = SMB_Get_Last_Error();
+    SMB_Get_Error_Msg(smberr, errstr, 100);
+
+
+    if (handle == NULL) {      /* couldn't connect */
+       debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
+       return 1;
+    }
+    if (SMB_Negotiate(handle, SMB_Prots) < 0) {                /* An error */
+       debug("Error negotiating protocol with SMB Server\n");
+       SMB_Discon(handle, 0);
+       handle = NULL;
+       return 2;
+    }
+    if (handle->Security == 0) {       /* share-level security, unuseable */
+       debug("SMB Server uses share-level security .. we need user sercurity.\n");
+       SMB_Discon(handle, 0);
+       handle = NULL;
+       return 3;
+    }
+    memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
+    return 0;
+}
+
+const char *
+make_challenge(char *domain, char *domain_controller)
+{
+    if (init_challenge(domain, domain_controller) > 0)
+       return NULL;
+    return ntlm_make_challenge(domain, domain_controller, challenge,
+       NONCE_LEN);
+}
+
+#define min(A,B) (A<B?A:B)
+/* returns NULL on failure, or a pointer to
+ * the user's credentials (domain\\username)
+ * upon success. WARNING. It's pointing to static storage.
+ * In case of problem sets as side-effect ntlm_errno to one of the
+ * codes defined in ntlm.h
+ */
+int ntlm_errno;
+static char credentials[1024]; /* we can afford to waste */
+char *
+ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
+{
+    int rv, retries = 0;
+    char pass[25];
+    char *domain = credentials;
+    char *user;
+    lstring tmp;
+
+    if (handle == NULL) {      /*if null we aren't connected, but it shouldn't happen */
+       debug("Weird, we've been disconnected\n");
+       ntlm_errno = NTLM_NOT_CONNECTED;
+       return NULL;
+    }
+    /* Authenticating against the NT response doesn't seem to work... */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
+    if (tmp.str == NULL) {
+       fprintf(stderr, "No auth at all. Returning no-auth\n");
+       ntlm_errno = NTLM_LOGON_ERROR;
+       return NULL;
+    }
+    memcpy(pass, tmp.str, tmp.l);
+    pass[25] = '\0';
+
+/*      debug("fetching domain\n"); */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+    if (tmp.str == NULL) {
+       debug("No domain supplied. Returning no-auth\n");
+       ntlm_errno = NTLM_LOGON_ERROR;
+       return NULL;
+    }
+    memcpy(domain, tmp.str, tmp.l);
+    user = domain + tmp.l;
+    *user++ = '\0';
+
+/*      debug("fetching user name\n"); */
+    tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+    if (tmp.str == NULL) {
+       debug("No username supplied. Returning no-auth\n");
+       ntlm_errno = NTLM_LOGON_ERROR;
+       return NULL;
+    }
+    memcpy(user, tmp.str, tmp.l);
+    *(user + tmp.l) = '\0';
+
+    debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
+
+    rv = SMB_Logon_Server(handle, user, pass, domain, 1);
+
+    while ((rv == NTLM_BAD_PROTOCOL || rv == NTLM_SERVER_ERROR)
+       && retries < BAD_DC_RETRIES_NUMBER) {
+       retries++;
+       usleep((unsigned long) 100000);
+       rv = SMB_Logon_Server(handle, user, pass, domain, 1);
+    }
+
+    debug("\tresult is %d\n", rv);
+
+    if (rv != NTV_NO_ERROR) {  /* failed */
+       ntlm_errno = rv;
+       return NULL;
+    }
+    *(user - 1) = '\\';
+
+    debug("credentials: %s\n", credentials);
+    return credentials;
+}
diff --git a/helpers/ntlm_auth/SMB/ntlm.h b/helpers/ntlm_auth/SMB/ntlm.h
new file mode 100644 (file)
index 0000000..65b6591
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *        inspired by previous work by Andy Doran
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef _NTLM_H_
+#define _NTLM_H_
+
+#include "config.h"
+#include "ntlmauth.h"
+
+/* for time_t */
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/************* CONFIGURATION ***************/
+/*
+ * define this if you want debugging
+ */
+#define DEBUG
+
+/*
+ * Number of authentication attempts to perform in case of certain errors
+ */
+#define BAD_DC_RETRIES_NUMBER 3
+
+/************* END CONFIGURATION ***************/
+
+#include <sys/types.h>
+
+
+/* Debugging stuff */
+
+#ifdef __GNUC__                        /* this is really a gcc-ism */
+#ifdef DEBUG
+#include <stdio.h>
+#include <unistd.h>
+static char *__foo;
+#define debug(X...) fprintf(stderr,"ntlm-auth[%d](%s:%d): ", getpid(), \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X)
+#else /* DEBUG */
+#define debug(X...)            /* */
+#endif /* DEBUG */
+#else /* __GNUC__ */
+#define debug(char *format, ...) {}    /* Too lazy to write va_args stuff */
+#endif
+
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X); printf("\n");
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X,Y);\
+         printf("\n");
+
+extern int ntlm_errno;
+#define NTLM_NO_ERROR 0
+#define NTLM_SERVER_ERROR 1
+#define NTLM_PROTOCOL_ERROR 2
+#define NTLM_LOGON_ERROR 3
+#define NTLM_BAD_PROTOCOL -1
+#define NTLM_NOT_CONNECTED 10
+
+
+const char *make_challenge(char *domain, char *controller);
+extern char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length);
+void dc_disconnect(void);
+int connectedp(void);
+int is_dc_ok(char *domain, char *domain_controller);
+
+/* flags used for dc status */
+#define DC_OK 0x0
+#define DC_DEAD 0x1
+
+typedef struct _dc dc;
+struct _dc {
+    char *domain;
+    char *controller;
+    unsigned char status;
+    dc *next;
+};
+
+
+#endif /* _NTLM_H_ */
diff --git a/helpers/ntlm_auth/SMB/ntlm_auth.c b/helpers/ntlm_auth/SMB/ntlm_auth.c
new file mode 100644 (file)
index 0000000..c965eed
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Warning! We MIGHT be open to buffer overflows caused by malformed headers
+ *
+ * DONE list:
+ * use hashtable to cache authentications. Yummy performance-boost, security
+ *  loss should be negligible for two reasons:
+ *   - if they-re using NT, there's no security to speak of anyways
+ *   - it can't get worse than basic authentication.
+ * cache expiration
+ * challenge hash expiry and renewal.
+ * PDC disconnect, after X minutes of inactivity
+ *
+ * TODO list:
+ * change syntax from options-driven to args-driven, with args domain
+ *   or domain[/\]server, and an arbitrary number of backup Domain Controllers
+ * we don't really need the "status" management, it's more for debugging
+ *  purposes. Remove it.
+ * Maybe we can cache the created challenge, saving more time?
+ *
+ */
+
+
+#include "config.h"
+#include "ntlmauth.h"
+#include "ntlm.h"
+#include "util.h"
+
+#define BUFFER_SIZE 10240
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+char load_balance = 0, failover_enabled = 0, protocol_pedantic = 0;
+
+dc *controllers = NULL;
+int numcontrollers = 0;
+dc *current_dc;
+
+/* housekeeping cycle and periodic operations */
+static unsigned char need_dc_resurrection = 0;
+static void
+resurrect_dead_dc()
+{
+    int j;
+    dc *c = controllers;
+
+    need_dc_resurrection = 0;
+    for (j = 0; j < numcontrollers; j++)
+       if (c->status != DC_OK && is_dc_ok(c->domain, c->controller))
+           c->status = DC_OK;
+}
+
+/* makes a null-terminated string upper-case. Changes CONTENTS! */
+static void
+uc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+       *p = toupper(c);
+       p++;
+    }
+}
+
+/* makes a null-terminated string lower-case. Changes CONTENTS! */
+static void
+lc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+       *p = tolower(c);
+       p++;
+    }
+}
+
+/*
+ * options:
+ * -b try load-balancing the domain-controllers
+ * -f fail-over to another DC if DC connection fails.
+ * domain\controller ...
+ */
+void
+process_options(int argc, char *argv[])
+{
+    int opt, j, had_error = 0;
+    dc *new_dc = NULL, *last_dc = NULL;
+    while (-1 != (opt = getopt(argc, argv, "bf"))) {
+       switch (opt) {
+       case 'b':
+           load_balance = 1;
+           break;
+       case 'f':
+           failover_enabled = 1;
+           break;
+       default:
+           fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
+           had_error = 1;
+       }
+    }
+    if (had_error)
+       exit(1);
+    /* Okay, now begin filling controllers up */
+    /* we can avoid memcpy-ing, and just reuse argv[] */
+    for (j = optind; j < argc; j++) {
+       char *d, *c;
+       d = argv[j];
+       if (NULL == (c = strchr(d, '\\')) && NULL == (c = strchr(d, '/'))) {
+           fprintf(stderr, "Couldn't grok domain-controller %s\n", d);
+           continue;
+       }
+       *c++ = '\0';
+       new_dc = (dc *) malloc(sizeof(dc));
+       if (!new_dc) {
+           fprintf(stderr, "Malloc error while parsing DC options\n");
+           continue;
+       }
+       /* capitalize */
+       uc(c);
+       uc(d);
+       numcontrollers++;
+       new_dc->domain = d;
+       new_dc->controller = c;
+       new_dc->status = DC_OK;
+       if (controllers == NULL) {      /* first controller */
+           controllers = new_dc;
+           last_dc = new_dc;
+       } else {
+           last_dc->next = new_dc;     /* can't be null */
+           last_dc = new_dc;
+       }
+    }
+    if (numcontrollers == 0) {
+       fprintf(stderr, "You must specify at least one domain-controller!\n");
+       exit(1);
+    }
+    last_dc->next = controllers;       /* close the queue, now it's circular */
+}
+
+/* tries connecting to the domain controllers in the "controllers" ring,
+ * with failover if the adequate option is specified.
+ */
+const char *
+obtain_challenge()
+{
+    int j = 0;
+    const char *ch;
+    for (j = 0; j < numcontrollers; j++) {
+       if (current_dc->status == DC_OK) {
+           ch = make_challenge(current_dc->domain, current_dc->controller);
+           if (ch)
+               return ch;      /* All went OK, returning */
+           /* Huston, we've got a problem. Take this DC out of the loop */
+           current_dc->status = DC_DEAD;
+           need_dc_resurrection = 1;
+       }
+       if (failover_enabled == 0)      /* No failover. Just return */
+           return NULL;
+       /* Try with the next */
+       current_dc = current_dc->next;
+    }
+    return NULL;
+}
+
+void
+manage_request()
+{
+    ntlmhdr *fast_header;
+    char buf[10240];
+    const char *ch;
+    char *ch2, *decoded, *cred;
+    int plen;
+
+    if (fgets(buf, BUFFER_SIZE, stdin) == NULL)
+       exit(0);                /* BIIG buffer */
+    ch2 = memchr(buf, '\n', BUFFER_SIZE);      /* safer against overrun than strchr */
+    if (ch2) {
+       *ch2 = '\0';            /* terminate the string at newline. */
+       ch = ch2;
+    }
+    debug("ntlm authenticator. Got '%s' from Squid\n", buf);
+
+    if (memcmp(buf, "KK ", 3) == 0) {  /* authenticate-request */
+       /* figure out what we got */
+       decoded = base64_decode(buf + 3);
+       /* Note: we don't need to manage memory at this point, since
+        *  base64_decode returns a pointer to static storage.
+        */
+
+       if (!decoded) {         /* decoding failure, return error */
+           SEND("NA Packet format error, couldn't base64-decode");
+           return;
+       }
+       /* fast-track-decode request type. */
+       fast_header = (struct _ntlmhdr *) decoded;
+
+       /* sanity-check: it IS a NTLMSSP packet, isn't it? */
+       if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) {
+           SEND("NA Broken authentication packet");
+           return;
+       }
+       switch (fast_header->type) {
+       case NTLM_NEGOTIATE:
+           SEND("NA Invalid negotiation request received");
+           return;
+           /* notreached */
+       case NTLM_CHALLENGE:
+           SEND("NA Got a challenge. We refuse to have our authority disputed");
+           return;
+           /* notreached */
+       case NTLM_AUTHENTICATE:
+           /* check against the DC */
+           plen = strlen(buf) * 3 / 4;         /* we only need it here. Optimization */
+           cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen);
+           if (cred == NULL) {
+               switch (ntlm_errno) {
+               case NTLM_LOGON_ERROR:
+                   SEND("NA authentication failure");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               case NTLM_SERVER_ERROR:
+                   SEND("BH Domain Controller Error");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               case NTLM_PROTOCOL_ERROR:
+                   SEND("BH Domain Controller communication error");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               case NTLM_NOT_CONNECTED:
+                   SEND("BH Domain Controller (or network) died on us");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               case NTLM_BAD_PROTOCOL:
+                   SEND("BH Domain controller failure");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               default:
+                   SEND("BH Unhandled error while talking to Domain Controller");
+                   dc_disconnect();
+                   current_dc = current_dc->next;
+                   return;
+               }
+           }
+           lc(cred);           /* let's lowercase them for our convenience */
+           SEND2("AF %s", cred);
+           return;
+       default:
+           SEND("BH unknown authentication packet type");
+           return;
+       }
+
+
+       return;
+    }
+    if (memcmp(buf, "YR", 2) == 0) {   /* refresh-request */
+       dc_disconnect();
+       ch = obtain_challenge();
+       while (ch == NULL) {
+           sleep(30);
+           ch = obtain_challenge();
+       }
+       SEND2("TT %s", ch);
+       if (need_dc_resurrection)       /* looks like a good moment... */
+           resurrect_dead_dc();
+       return;
+    }
+    SEND("BH Helper detected protocol error");
+    return;
+/********* END ********/
+
+
+}
+
+int
+main(int argc, char *argv[])
+{
+
+    debug("starting up...\n");
+
+    process_options(argc, argv);
+
+    debug("options processed OK\n");
+
+    /* initialize FDescs */
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+
+    /* select the first domain controller we're going to use */
+    current_dc = controllers;
+    if (load_balance != 0 && numcontrollers > 1) {
+       int n;
+       pid_t pid = getpid();
+       n = pid % numcontrollers;
+       debug("load balancing. Selected controller #%d\n", n);
+       while (n > 0) {
+           current_dc = current_dc->next;
+           n--;
+       }
+    }
+    while (1) {
+       debug("managing request\n");
+       manage_request();
+    }
+    return 0;
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/Makefile.in b/helpers/ntlm_auth/SMB/smbval/Makefile.in
new file mode 100644 (file)
index 0000000..491a664
--- /dev/null
@@ -0,0 +1,52 @@
+# makefile for smblib
+# Type make system, where system is ULTRIX, DU, DECOSF1, Solaris etc
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+CC              = @CC@
+MAKEDEPEND      = @MAKEDEPEND@
+INSTALL         = @INSTALL@
+INSTALL_BIN     = @INSTALL_PROGRAM@
+INSTALL_FILE    = @INSTALL_DATA@
+RANLIB          = @RANLIB@
+AC_CFLAGS       = @CFLAGS@
+LDFLAGS         = @LDFLAGS@
+XTRA_LIBS       = @XTRA_LIBS@
+RM              = @RM@
+AR_R           = @AR_R@
+
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+# CFLAGS = -fpic -g
+
+INCLUDE  = -I. -I../../../../../../include -I$(top_srcdir)/include
+INCLUDES = smblib.h smblib-priv.h
+
+#RFCNB = session.o rfcnb-util.o rfcnb-io.o
+
+#OBJS = smblib.o smblib-util.o file.o smb-errors.o exper.o smblib-api.o smbencrypt.o smbdes.o md4.o
+
+VALIDATE = valid.o session.o rfcnb-util.o \
+           rfcnb-io.o smblib-util.o smblib.o smbencrypt.o smbdes.o md4.o
+
+#.SUFFIXES: .c .o .h
+
+dummy: all
+
+smbvalid.a:    $(VALIDATE) 
+       $(RM) -f $@
+       $(AR_R) $@ $(VALIDATE)
+       $(RANLIB) $@
+
+all: smbvalid.a
+
+#.c.o: $(INCLUDES)
+
+clean:
+       $(RM) -f *.o smbvalid.a *~
+
diff --git a/helpers/ntlm_auth/SMB/smbval/byteorder.h b/helpers/ntlm_auth/SMB/smbval/byteorder.h
new file mode 100644 (file)
index 0000000..ab2578c
--- /dev/null
@@ -0,0 +1,80 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB Byte handling
+ * Copyright (C) Andrew Tridgell 1992-1995
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file implements macros for machine independent short and 
+ * int manipulation
+ */
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+ * byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
+
+
+#if CAREFUL_ALIGNMENT
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+#else
+/* this handles things for architectures like the 386 that can handle
+ * alignment errors */
+/*
+ * WARNING: This section is dependent on the length of int16 and int32
+ * being correct 
+ */
+#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
+#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
+#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
+#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
+#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
+#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
+#endif
+
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
diff --git a/helpers/ntlm_auth/SMB/smbval/md4.c b/helpers/ntlm_auth/SMB/smbval/md4.c
new file mode 100644 (file)
index 0000000..4586c70
--- /dev/null
@@ -0,0 +1,210 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * a implementation of MD4 designed for use in the SMB authentication protocol
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTE: This code makes no attempt to be fast! 
+ * 
+ * It assumes that a int is at least 32 bits long
+ */
+#include <string.h>
+
+typedef unsigned int uint32;
+
+static uint32 A, B, C, D;
+
+static uint32
+F(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | ((~X) & Z);
+}
+
+static uint32
+G(uint32 X, uint32 Y, uint32 Z)
+{
+    return (X & Y) | (X & Z) | (Y & Z);
+}
+
+static uint32
+H(uint32 X, uint32 Y, uint32 Z)
+{
+    return X ^ Y ^ Z;
+}
+
+static uint32
+lshift(uint32 x, int s)
+{
+    x &= 0xFFFFFFFF;
+    return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void
+mdfour64(uint32 * M)
+{
+    int j;
+    uint32 AA, BB, CC, DD;
+    uint32 X[16];
+
+    for (j = 0; j < 16; j++)
+       X[j] = M[j];
+
+    AA = A;
+    BB = B;
+    CC = C;
+    DD = D;
+
+    ROUND1(A, B, C, D, 0, 3);
+    ROUND1(D, A, B, C, 1, 7);
+    ROUND1(C, D, A, B, 2, 11);
+    ROUND1(B, C, D, A, 3, 19);
+    ROUND1(A, B, C, D, 4, 3);
+    ROUND1(D, A, B, C, 5, 7);
+    ROUND1(C, D, A, B, 6, 11);
+    ROUND1(B, C, D, A, 7, 19);
+    ROUND1(A, B, C, D, 8, 3);
+    ROUND1(D, A, B, C, 9, 7);
+    ROUND1(C, D, A, B, 10, 11);
+    ROUND1(B, C, D, A, 11, 19);
+    ROUND1(A, B, C, D, 12, 3);
+    ROUND1(D, A, B, C, 13, 7);
+    ROUND1(C, D, A, B, 14, 11);
+    ROUND1(B, C, D, A, 15, 19);
+
+    ROUND2(A, B, C, D, 0, 3);
+    ROUND2(D, A, B, C, 4, 5);
+    ROUND2(C, D, A, B, 8, 9);
+    ROUND2(B, C, D, A, 12, 13);
+    ROUND2(A, B, C, D, 1, 3);
+    ROUND2(D, A, B, C, 5, 5);
+    ROUND2(C, D, A, B, 9, 9);
+    ROUND2(B, C, D, A, 13, 13);
+    ROUND2(A, B, C, D, 2, 3);
+    ROUND2(D, A, B, C, 6, 5);
+    ROUND2(C, D, A, B, 10, 9);
+    ROUND2(B, C, D, A, 14, 13);
+    ROUND2(A, B, C, D, 3, 3);
+    ROUND2(D, A, B, C, 7, 5);
+    ROUND2(C, D, A, B, 11, 9);
+    ROUND2(B, C, D, A, 15, 13);
+
+    ROUND3(A, B, C, D, 0, 3);
+    ROUND3(D, A, B, C, 8, 9);
+    ROUND3(C, D, A, B, 4, 11);
+    ROUND3(B, C, D, A, 12, 15);
+    ROUND3(A, B, C, D, 2, 3);
+    ROUND3(D, A, B, C, 10, 9);
+    ROUND3(C, D, A, B, 6, 11);
+    ROUND3(B, C, D, A, 14, 15);
+    ROUND3(A, B, C, D, 1, 3);
+    ROUND3(D, A, B, C, 9, 9);
+    ROUND3(C, D, A, B, 5, 11);
+    ROUND3(B, C, D, A, 13, 15);
+    ROUND3(A, B, C, D, 3, 3);
+    ROUND3(D, A, B, C, 11, 9);
+    ROUND3(C, D, A, B, 7, 11);
+    ROUND3(B, C, D, A, 15, 15);
+
+    A += AA;
+    B += BB;
+    C += CC;
+    D += DD;
+
+    A &= 0xFFFFFFFF;
+    B &= 0xFFFFFFFF;
+    C &= 0xFFFFFFFF;
+    D &= 0xFFFFFFFF;
+
+    for (j = 0; j < 16; j++)
+       X[j] = 0;
+}
+
+static void
+copy64(uint32 * M, unsigned char *in)
+{
+    int i;
+
+    for (i = 0; i < 16; i++)
+       M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
+           (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
+}
+
+static void
+copy4(unsigned char *out, uint32 x)
+{
+    out[0] = x & 0xFF;
+    out[1] = (x >> 8) & 0xFF;
+    out[2] = (x >> 16) & 0xFF;
+    out[3] = (x >> 24) & 0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void
+mdfour(unsigned char *out, unsigned char *in, int n)
+{
+    unsigned char buf[128];
+    uint32 M[16];
+    uint32 b = n * 8;
+    int i;
+
+    A = 0x67452301;
+    B = 0xefcdab89;
+    C = 0x98badcfe;
+    D = 0x10325476;
+
+    while (n > 64) {
+       copy64(M, in);
+       mdfour64(M);
+       in += 64;
+       n -= 64;
+    }
+
+    for (i = 0; i < 128; i++)
+       buf[i] = 0;
+    memcpy(buf, in, n);
+    buf[n] = 0x80;
+
+    if (n <= 55) {
+       copy4(buf + 56, b);
+       copy64(M, buf);
+       mdfour64(M);
+    } else {
+       copy4(buf + 120, b);
+       copy64(M, buf);
+       mdfour64(M);
+       copy64(M, buf + 64);
+       mdfour64(M);
+    }
+
+    for (i = 0; i < 128; i++)
+       buf[i] = 0;
+    copy64(M, buf);
+
+    copy4(out, A);
+    copy4(out + 4, B);
+    copy4(out + 8, C);
+    copy4(out + 12, D);
+
+    A = B = C = D = 0;
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/md4.h b/helpers/ntlm_auth/SMB/smbval/md4.h
new file mode 100644 (file)
index 0000000..015b849
--- /dev/null
@@ -0,0 +1 @@
+void mdfour(unsigned char *out, unsigned char *in, int n);
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-common.h b/helpers/ntlm_auth/SMB/smbval/rfcnb-common.h
new file mode 100644 (file)
index 0000000..a56a539
--- /dev/null
@@ -0,0 +1,34 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Common Structures etc Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* A data structure we need */
+
+typedef struct RFCNB_Pkt {
+
+    char *data;                        /* The data in this portion */
+    int len;
+    struct RFCNB_Pkt *next;
+
+} RFCNB_Pkt;
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-error.h b/helpers/ntlm_auth/SMB/smbval/rfcnb-error.h
new file mode 100644 (file)
index 0000000..14eb6c6
--- /dev/null
@@ -0,0 +1,74 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Error Response Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Error responses */
+
+#define RFCNBE_Bad -1          /* Bad response */
+#define RFCNBE_OK 0
+
+/* these should follow the spec ... is there one ? */
+
+#define RFCNBE_NoSpace 1       /* Could not allocate space for a struct */
+#define RFCNBE_BadName 2       /* Could not translate a name            */
+#define RFCNBE_BadRead 3       /* Read sys call failed                  */
+#define RFCNBE_BadWrite 4      /* Write Sys call failed                 */
+#define RFCNBE_ProtErr 5       /* Protocol Error                        */
+#define RFCNBE_ConGone 6       /* Connection dropped                    */
+#define RFCNBE_BadHandle 7     /* Handle passed was bad                 */
+#define RFCNBE_BadSocket 8     /* Problems creating socket              */
+#define RFCNBE_ConnectFailed 9 /* Connect failed                        */
+#define RFCNBE_CallRejNLOCN 10 /* Call rejected, not listening on CN    */
+#define RFCNBE_CallRejNLFCN 11 /* Call rejected, not listening for CN   */
+#define RFCNBE_CallRejCNNP  12 /* Call rejected, called name not present */
+#define RFCNBE_CallRejInfRes 13        /* Call rejetced, name ok, no resources   */
+#define RFCNBE_CallRejUnSpec 14        /* Call rejected, unspecified error      */
+#define RFCNBE_BadParam      15        /* Bad parameters passed ...             */
+#define RFCNBE_Timeout       16        /* IO Timed out                          */
+
+/* Text strings for the error responses                                 */
+extern char *RFCNB_Error_Strings[];
+/*
+ * static char *RFCNB_Error_Strings[] = {
+ * 
+ * "RFCNBE_OK: Routine completed successfully.",
+ * "RFCNBE_NoSpace: No space available for a malloc call.",
+ * "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+ * "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+ * "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+ * "RFCNBE_ProtErr: A protocol error has occurred.",
+ * "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+ * "RFCNBE_BadHandle: Bad connection handle passed.",
+ * "RFCNBE_BadSocket: Problems creating socket.",
+ * "RFCNBE_ConnectFailed: Connection failed. See errno.",
+ * "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+ * "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+ * "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+ * "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+ * "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+ * "RFCNBE_BadParam: Bad parameters passed to a routine.",
+ * "RFCNBE_Timeout: IO Operation timed out ..."
+ * 
+ * };
+ */
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-io.c b/helpers/ntlm_auth/SMB/smbval/rfcnb-io.c
new file mode 100644 (file)
index 0000000..06ed1ee
--- /dev/null
@@ -0,0 +1,400 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* #include <features.h> */
+#include "config.h"
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <sys/uio.h>
+#include <sys/signal.h>
+#include <string.h>
+
+int RFCNB_Timeout = 0;         /* Timeout in seconds ... */
+
+void
+rfcnb_alarm(int sig)
+{
+
+    fprintf(stderr, "IO Timed out ...\n");
+
+}
+
+/* Set timeout value and setup signal handling */
+
+int
+RFCNB_Set_Timeout(int seconds)
+{
+    /* If we are on a Bezerkeley system, use sigvec, else sigaction */
+#if HAVE_SIGACTION
+    struct sigaction inact, outact;
+#else
+    struct sigvec invec, outvec;
+#endif
+
+    RFCNB_Timeout = seconds;
+
+    if (RFCNB_Timeout > 0) {   /* Set up handler to ignore but not restart */
+
+#if HAVE_SIGACTION
+       inact.sa_handler = (void (*)()) rfcnb_alarm;
+       sigemptyset(&inact.sa_mask);
+       inact.sa_flags = 0;     /* Don't restart */
+
+       if (sigaction(SIGALRM, &inact, &outact) < 0)
+           return (-1);
+#else
+       invec.sv_handler = (void (*)()) rfcnb_alarm;
+       invec.sv_mask = 0;
+       invec.sv_flags = SV_INTERRUPT;
+
+       if (sigvec(SIGALRM, &invec, &outvec) < 0)
+           return (-1);
+#endif
+
+    }
+    return (0);
+
+}
+
+/* Discard the rest of an incoming packet as we do not have space for it
+ * in the buffer we allocated or were passed ...                         */
+
+int
+RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
+{
+    char temp[100];            /* Read into here */
+    int rest, this_read, bytes_read;
+
+    /* len is the amount we should read */
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
+#endif
+
+    rest = len;
+
+    while (rest > 0) {
+
+       this_read = (rest > sizeof(temp) ? sizeof(temp) : rest);
+
+       bytes_read = read(con->fd, temp, this_read);
+
+       if (bytes_read <= 0) {  /* Error so return */
+
+           if (bytes_read < 0)
+               RFCNB_errno = RFCNBE_BadRead;
+           else
+               RFCNB_errno = RFCNBE_ConGone;
+
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       rest = rest - bytes_read;
+
+    }
+
+    return (0);
+
+}
+
+
+/* Send an RFCNB packet to the connection.
+ * 
+ * We just send each of the blocks linked together ... 
+ * 
+ * If we can, try to send it as one iovec ... 
+ * 
+ */
+
+int
+RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int len_sent, tot_sent, this_len;
+    struct RFCNB_Pkt *pkt_ptr;
+    char *this_data;
+    int i;
+    struct iovec io_list[10];  /* We should never have more      */
+    /* If we do, this will blow up ... */
+
+    /* Try to send the data ... We only send as many bytes as len claims */
+    /* We should try to stuff it into an IOVEC and send as one write     */
+
+
+    pkt_ptr = pkt;
+    len_sent = tot_sent = 0;   /* Nothing sent so far */
+    i = 0;
+
+    while ((pkt_ptr != NULL) & (i < 10)) {     /* Watch that magic number! */
+
+       this_len = pkt_ptr->len;
+       this_data = pkt_ptr->data;
+       if ((tot_sent + this_len) > len)
+           this_len = len - tot_sent;  /* Adjust so we don't send too much */
+
+       /* Now plug into the iovec ... */
+
+       io_list[i].iov_len = this_len;
+       io_list[i].iov_base = this_data;
+       i++;
+
+       tot_sent += this_len;
+
+       if (tot_sent == len)
+           break;              /* Let's not send too much */
+
+       pkt_ptr = pkt_ptr->next;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
+#endif
+
+    /* Set up an alarm if timeouts are set ... */
+
+    if (RFCNB_Timeout > 0)
+       alarm(RFCNB_Timeout);
+
+    if ((len_sent = writev(con->fd, io_list, i)) < 0) {                /* An error */
+
+       con->rfc_errno = errno;
+       if (errno == EINTR)     /* We were interrupted ... */
+           RFCNB_errno = RFCNBE_Timeout;
+       else
+           RFCNB_errno = RFCNBE_BadWrite;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    if (len_sent < tot_sent) { /* Less than we wanted */
+       if (errno == EINTR)     /* We were interrupted */
+           RFCNB_errno = RFCNBE_Timeout;
+       else
+           RFCNB_errno = RFCNBE_BadWrite;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    if (RFCNB_Timeout > 0)
+       alarm(0);               /* Reset that sucker */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Len sent = %i ...\n", len_sent);
+    RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent);    /* Print what send ... */
+
+#endif
+
+    return (len_sent);
+
+}
+
+/* Read an RFCNB packet off the connection. 
+ * 
+ * We read the first 4 bytes, that tells us the length, then read the
+ * rest. We should implement a timeout, but we don't just yet 
+ * 
+ */
+
+
+int
+RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+{
+    int read_len, pkt_len;
+    char hdr[RFCNB_Pkt_Hdr_Len];       /* Local space for the header */
+    struct RFCNB_Pkt *pkt_frag;
+    int more, this_time, offset, frag_len, this_len;
+    BOOL seen_keep_alive = TRUE;
+
+    /* Read that header straight into the buffer */
+
+    if (len < RFCNB_Pkt_Hdr_Len) {     /* What a bozo */
+
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Trying to read less than a packet:");
+       perror("");
+#endif
+       RFCNB_errno = RFCNBE_BadParam;
+       return (RFCNBE_Bad);
+
+    }
+    /* We discard keep alives here ... */
+
+    if (RFCNB_Timeout > 0)
+       alarm(RFCNB_Timeout);
+
+    while (seen_keep_alive) {
+
+       if ((read_len = read(con->fd, hdr, sizeof(hdr))) < 0) {         /* Problems */
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "Reading the packet, we got:");
+           perror("");
+#endif
+           if (errno == EINTR)
+               RFCNB_errno = RFCNBE_Timeout;
+           else
+               RFCNB_errno = RFCNBE_BadRead;
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       /* Now we check out what we got */
+
+       if (read_len == 0) {    /* Connection closed, send back eof?  */
+
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "Connection closed reading\n");
+#endif
+
+           if (errno == EINTR)
+               RFCNB_errno = RFCNBE_Timeout;
+           else
+               RFCNB_errno = RFCNBE_ConGone;
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+       if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
+
+#ifdef RFCNB_DEBUG
+           fprintf(stderr, "RFCNB KEEP ALIVE received\n");
+#endif
+
+       } else {
+           seen_keep_alive = FALSE;
+       }
+
+    }
+
+    /* What if we got less than or equal to a hdr size in bytes? */
+
+    if (read_len < sizeof(hdr)) {      /* We got a small packet */
+
+       /* Now we need to copy the hdr portion we got into the supplied packet */
+
+       memcpy(pkt->data, hdr, read_len);       /*Copy data */
+
+#ifdef RFCNB_DEBUG
+       RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
+#endif
+
+       return (read_len);
+
+    }
+    /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
+
+    pkt_len = RFCNB_Pkt_Len(hdr);
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
+#endif
+
+    /* Now copy in the hdr */
+
+    memcpy(pkt->data, hdr, sizeof(hdr));
+
+    /* Get the rest of the packet ... first figure out how big our buf is? */
+    /* And make sure that we handle the fragments properly ... Sure should */
+    /* use an iovec ...                                                    */
+
+    if (len < pkt_len)         /* Only get as much as we have space for */
+       more = len - RFCNB_Pkt_Hdr_Len;
+    else
+       more = pkt_len;
+
+    this_time = 0;
+
+    /* We read for each fragment ... */
+
+    if (pkt->len == read_len) {        /* If this frag was exact size */
+       pkt_frag = pkt->next;   /* Stick next lot in next frag */
+       offset = 0;             /* then we start at 0 in next  */
+    } else {
+       pkt_frag = pkt;         /* Otherwise use rest of this frag */
+       offset = RFCNB_Pkt_Hdr_Len;     /* Otherwise skip the header       */
+    }
+
+    frag_len = pkt_frag->len;
+
+    if (more <= frag_len)      /* If len left to get less than frag space */
+       this_len = more;        /* Get the rest ...                        */
+    else
+       this_len = frag_len - offset;
+
+    while (more > 0) {
+
+       if ((this_time = read(con->fd, (pkt_frag->data) + offset, this_len)) <= 0) {    /* Problems */
+
+           if (errno == EINTR) {
+
+               RFCNB_errno = RFCNB_Timeout;
+
+           } else {
+               if (this_time < 0)
+                   RFCNB_errno = RFCNBE_BadRead;
+               else
+                   RFCNB_errno = RFCNBE_ConGone;
+           }
+
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       }
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
+           this_time, this_len, more);
+#endif
+
+       read_len = read_len + this_time;        /* How much have we read ... */
+
+       /* Now set up the next part */
+
+       if (pkt_frag->next == NULL)
+           break;              /* That's it here */
+
+       pkt_frag = pkt_frag->next;
+       this_len = pkt_frag->len;
+       offset = 0;
+
+       more = more - this_time;
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
+    RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
+#endif
+
+    if (read_len < (pkt_len + sizeof(hdr))) {  /* Discard the rest */
+
+       return (RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
+
+    }
+    if (RFCNB_Timeout > 0)
+       alarm(0);               /* Reset that sucker */
+
+    return (read_len + sizeof(RFCNB_Hdr));
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-io.h b/helpers/ntlm_auth/SMB/smbval/rfcnb-io.h
new file mode 100644 (file)
index 0000000..40a96b3
--- /dev/null
@@ -0,0 +1,30 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB IO Routines Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-priv.h b/helpers/ntlm_auth/SMB/smbval/rfcnb-priv.h
new file mode 100644 (file)
index 0000000..766a66f
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef __RFCNB_H__
+#define __RFCNB_H__
+
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Defines we need */
+
+typedef unsigned short uint16;
+
+#define GLOBAL extern
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "byteorder.h"
+
+#ifdef RFCNB_PORT
+#define RFCNB_Default_Port RFCNB_PORT
+#else
+#define RFCNB_Default_Port 139
+#endif
+
+#define RFCNB_MAX_STATS 1
+
+/* Protocol defines we need */
+
+#define RFCNB_SESSION_MESSAGE 0
+#define RFCNB_SESSION_REQUEST 0x81
+#define RFCNB_SESSION_ACK 0x82
+#define RFCNB_SESSION_REJ 0x83
+#define RFCNB_SESSION_RETARGET 0x84
+#define RFCNB_SESSION_KEEP_ALIVE 0x85
+
+/* Structures      */
+
+typedef struct redirect_addr *redirect_ptr;
+
+struct redirect_addr {
+
+    struct in_addr ip_addr;
+    int port;
+    redirect_ptr next;
+
+};
+
+typedef struct RFCNB_Con {
+
+    int fd;                    /* File descripter for TCP/IP connection */
+    int rfc_errno;             /* last error                            */
+    int timeout;               /* How many milli-secs before IO times out */
+    int redirects;             /* How many times we were redirected     */
+    struct redirect_addr *redirect_list;       /* First is first address */
+    struct redirect_addr *last_addr;
+
+} RFCNB_Con;
+
+typedef char RFCNB_Hdr[4];     /* The header is 4 bytes long with  */
+                                   /* char[0] as the type, char[1] the */
+                                   /* flags, and char[2..3] the length */
+
+/* Macros to extract things from the header. These are for portability
+ * between architecture types where we are worried about byte order     */
+
+#define RFCNB_Pkt_Hdr_Len        4
+#define RFCNB_Pkt_Sess_Len       72
+#define RFCNB_Pkt_Retarg_Len     10
+#define RFCNB_Pkt_Nack_Len       5
+#define RFCNB_Pkt_Type_Offset    0
+#define RFCNB_Pkt_Flags_Offset   1
+#define RFCNB_Pkt_Len_Offset     2     /* Length is 2 bytes plus a flag bit */
+#define RFCNB_Pkt_N1Len_Offset   4
+#define RFCNB_Pkt_Called_Offset  5
+#define RFCNB_Pkt_N2Len_Offset   38
+#define RFCNB_Pkt_Calling_Offset 39
+#define RFCNB_Pkt_Error_Offset   4
+#define RFCNB_Pkt_IP_Offset      4
+#define RFCNB_Pkt_Port_Offset    8
+
+/* The next macro isolates the length of a packet, including the bit in the
+ * flags                                                                   */
+
+#define RFCNB_Pkt_Len(p)  (PVAL(p, 3) | (PVAL(p, 2) << 8) |     \
+                          ((PVAL(p, RFCNB_Pkt_Flags_Offset) & 0x01) << 16))
+
+#define RFCNB_Put_Pkt_Len(p, v) (p[1] = (((v) >> 16) & 1)); \
+                               (p[2] = (((v) >> 8) & 0xFF)); \
+                               (p[3] = ((v) & 0xFF));
+
+#define RFCNB_Pkt_Type(p) (CVAL(p, RFCNB_Pkt_Type_Offset))
+
+/*typedef struct RFCNB_Hdr {
+ * 
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 len;
+ * 
+ * } RFCNB_Hdr;
+ * 
+ * typedef struct RFCNB_Sess_Pkt {
+ * unsigned char type;
+ * unsigned char flags;
+ * int16 length;
+ * unsigned char n1_len;
+ * char called_name[33];
+ * unsigned char n2_len;
+ * char calling_name[33];
+ * } RFCNB_Sess_Pkt;
+ * 
+ * 
+ * typedef struct RFCNB_Nack_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * unsigned char error;
+ * 
+ * } RFCNB_Nack_Pkt;
+ * 
+ * typedef struct RFCNB_Retarget_Pkt {
+ * 
+ * struct RFCNB_Hdr hdr;
+ * int dest_ip;
+ * unsigned char port;
+ * 
+ * } RFCNB_Redir_Pkt; */
+
+/* Static variables */
+
+/* Only declare this if not defined */
+
+#ifndef RFCNB_ERRNO
+extern int RFCNB_errno;
+extern int RFCNB_saved_errno;  /* Save this from point of error */
+#endif
+
+#endif /* __RFCNB_H__ */
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-util.c b/helpers/ntlm_auth/SMB/smbval/rfcnb-util.c
new file mode 100644 (file)
index 0000000..5df94e3
--- /dev/null
@@ -0,0 +1,529 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <malloc.h>
+
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <arpa/inet.h>
+
+
+extern void (*Prot_Print_Routine) ();  /* Pointer to protocol print routine */
+
+/* Convert name and pad to 16 chars as needed */
+/* Name 1 is a C string with null termination, name 2 may not be */
+/* If SysName is true, then put a <00> on end, else space>       */
+
+void
+RFCNB_CvtPad_Name(char *name1, char *name2)
+{
+    char c, c1, c2;
+    int i, len;
+
+    len = strlen(name1);
+
+    for (i = 0; i < 16; i++) {
+
+       if (i >= len) {
+
+           c1 = 'C';
+           c2 = 'A';           /* CA is a space */
+
+       } else {
+
+           c = name1[i];
+           c1 = (char) ((int) c / 16 + (int) 'A');
+           c2 = (char) ((int) c % 16 + (int) 'A');
+       }
+
+       name2[i * 2] = c1;
+       name2[i * 2 + 1] = c2;
+
+    }
+
+    name2[32] = 0;             /* Put in the nll ... */
+
+}
+
+/* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
+ * Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
+ * to produce the next byte in the name.
+ * 
+ * This routine assumes that AName is 16 bytes long and that NBName has 
+ * space for 32 chars, so be careful ... 
+ * 
+ */
+
+void
+RFCNB_AName_To_NBName(char *AName, char *NBName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+       c = AName[i];
+
+       c1 = (char) ((c >> 4) + 'A');
+       c2 = (char) ((c & 0xF) + 'A');
+
+       NBName[i * 2] = c1;
+       NBName[i * 2 + 1] = c2;
+    }
+
+    NBName[32] = 0;            /* Put in a null */
+
+}
+
+/* Do the reverse of the above ... */
+
+void
+RFCNB_NBName_To_AName(char *NBName, char *AName)
+{
+    char c, c1, c2;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+
+       c1 = NBName[i * 2];
+       c2 = NBName[i * 2 + 1];
+
+       c = (char) (((int) c1 - (int) 'A') * 16 + ((int) c2 - (int) 'A'));
+
+       AName[i] = c;
+
+    }
+
+    AName[i] = 0;              /* Put a null on the end ... */
+
+}
+
+/* Print a string of bytes in HEX etc */
+
+void
+RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
+{
+    char c1, c2, outbuf1[33];
+    unsigned char c;
+    int i, j;
+    struct RFCNB_Pkt *pkt_ptr = pkt;
+    static char Hex_List[17] = "0123456789ABCDEF";
+
+    j = 0;
+
+    /* We only want to print as much as sepcified in Len */
+
+    while (pkt_ptr != NULL) {
+
+       for (i = 0;
+           i < ((Len > (pkt_ptr->len) ? pkt_ptr->len : Len) - Offset);
+           i++) {
+
+           c = pkt_ptr->data[i + Offset];
+           c1 = Hex_List[c >> 4];
+           c2 = Hex_List[c & 0xF];
+
+           outbuf1[j++] = c1;
+           outbuf1[j++] = c2;
+
+           if (j == 32) {      /* Print and reset */
+               outbuf1[j] = 0;
+               fprintf(fd, "    %s\n", outbuf1);
+               j = 0;
+           }
+       }
+
+       Offset = 0;
+       Len = Len - pkt_ptr->len;       /* Reduce amount by this much */
+       pkt_ptr = pkt_ptr->next;
+
+    }
+
+    /* Print last lot in the buffer ... */
+
+    if (j > 0) {
+
+       outbuf1[j] = 0;
+       fprintf(fd, "    %s\n", outbuf1);
+
+    }
+    fprintf(fd, "\n");
+
+}
+
+/* Get a packet of size n */
+
+struct RFCNB_Pkt *
+RFCNB_Alloc_Pkt(int n)
+{
+    RFCNB_Pkt *pkt;
+
+    if ((pkt = (struct RFCNB_Pkt *) malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (NULL);
+
+    }
+    pkt->next = NULL;
+    pkt->len = n;
+
+    if (n == 0)
+       return (pkt);
+
+    if ((pkt->data = (char *) malloc(n)) == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       free(pkt);
+       return (NULL);
+
+    }
+    return (pkt);
+
+}
+
+/* Free up a packet */
+
+void
+RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
+{
+    struct RFCNB_Pkt *pkt_next;
+    char *data_ptr;
+
+    while (pkt != NULL) {
+
+       pkt_next = pkt->next;
+
+       data_ptr = pkt->data;
+
+       if (data_ptr != NULL)
+           free(data_ptr);
+
+       free(pkt);
+
+       pkt = pkt_next;
+
+    }
+
+}
+
+/* Print an RFCNB packet */
+
+void
+RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
+{
+    char lname[17];
+
+    /* We assume that the first fragment is the RFCNB Header  */
+    /* We should loop through the fragments printing them out */
+
+    fprintf(fd, "RFCNB Pkt %s:", dirn);
+
+    switch (RFCNB_Pkt_Type(pkt->data)) {
+
+    case RFCNB_SESSION_MESSAGE:
+
+       fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt->data));
+       RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
+#ifdef RFCNB_PRINT_DATA
+           RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+#else
+           40);
+#endif
+
+       if (Prot_Print_Routine != 0) {  /* Print the rest of the packet */
+
+           Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
+               RFCNB_Pkt_Len(pkt->data) - RFCNB_Pkt_Hdr_Len);
+
+       }
+       break;
+
+    case RFCNB_SESSION_REQUEST:
+
+       fprintf(fd, "SESSION REQUEST: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+       RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Called_Offset), lname);
+       fprintf(fd, "  Called Name: %s\n", lname);
+       RFCNB_NBName_To_AName((char *) (pkt->data + RFCNB_Pkt_Calling_Offset), lname);
+       fprintf(fd, "  Calling Name: %s\n", lname);
+
+       break;
+
+    case RFCNB_SESSION_ACK:
+
+       fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       break;
+
+    case RFCNB_SESSION_REJ:
+       fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       if (RFCNB_Pkt_Len(pkt->data) < 1) {
+           fprintf(fd, "   Protocol Error, short Reject packet!\n");
+       } else {
+           fprintf(fd, "   Error = %x\n", CVAL(pkt->data, RFCNB_Pkt_Error_Offset));
+       }
+
+       break;
+
+    case RFCNB_SESSION_RETARGET:
+
+       fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+
+       /* Print out the IP address etc and the port? */
+
+       break;
+
+    case RFCNB_SESSION_KEEP_ALIVE:
+
+       fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
+           RFCNB_Pkt_Len(pkt->data));
+       break;
+
+    default:
+
+       break;
+    }
+
+}
+
+/* Resolve a name into an address */
+
+int
+RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
+{
+    int addr;                  /* Assumes IP4, 32 bit network addresses */
+    struct hostent *hp;
+
+    /* Use inet_addr to try to convert the address */
+
+    if ((addr = inet_addr(host)) == INADDR_NONE) {     /* Oh well, a good try :-) */
+
+       /* Now try a name look up with gethostbyname */
+
+       if ((hp = gethostbyname(host)) == NULL) {       /* Not in DNS */
+
+           /* Try NetBIOS name lookup, how the hell do we do that? */
+
+           RFCNB_errno = RFCNBE_BadName;       /* Is this right? */
+           RFCNB_saved_errno = errno;
+           return (RFCNBE_Bad);
+
+       } else {                /* We got a name */
+
+           memcpy((void *) Dest_IP, (void *) hp->h_addr_list[0], sizeof(struct in_addr));
+
+       }
+    } else {                   /* It was an IP address */
+
+       memcpy((void *) Dest_IP, (void *) &addr, sizeof(struct in_addr));
+
+    }
+
+    return 0;
+
+}
+
+/* Disconnect the TCP connection to the server */
+
+int
+RFCNB_Close(int socket)
+{
+
+    close(socket);
+
+    /* If we want to do error recovery, here is where we put it */
+
+    return 0;
+
+}
+
+/* Connect to the server specified in the IP address.
+ * Not sure how to handle socket options etc.         */
+
+int
+RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
+{
+    struct sockaddr_in Socket;
+    int fd;
+
+    /* Create a socket */
+
+    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {  /* Handle the error */
+
+       RFCNB_errno = RFCNBE_BadSocket;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    bzero((char *) &Socket, sizeof(Socket));
+    memcpy((char *) &Socket.sin_addr, (char *) &Dest_IP, sizeof(Dest_IP));
+
+    Socket.sin_port = htons(port);
+    Socket.sin_family = PF_INET;
+
+    /* Now connect to the destination */
+
+    if (connect(fd, (struct sockaddr *) &Socket, sizeof(Socket)) < 0) {                /* Error */
+
+       close(fd);
+       RFCNB_errno = RFCNBE_ConnectFailed;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+    }
+    return (fd);
+
+}
+
+/* handle the details of establishing the RFCNB session with remote 
+ * end 
+ * 
+ */
+
+int
+RFCNB_Session_Req(struct RFCNB_Con *con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port)
+{
+    char *sess_pkt;
+
+    /* Response packet should be no more than 9 bytes, make 16 jic */
+
+    char resp[16];
+    int len;
+    struct RFCNB_Pkt *pkt, res_pkt;
+
+    /* We build and send the session request, then read the response */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
+
+    if (pkt == NULL) {
+
+       return (RFCNBE_Bad);    /* Leave the error that RFCNB_Alloc_Pkt gives) */
+
+    }
+    sess_pkt = pkt->data;      /* Get pointer to packet proper */
+
+    sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
+    RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len - RFCNB_Pkt_Hdr_Len);
+    sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
+    sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
+
+    RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
+    RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
+
+    /* Now send the packet */
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
+
+       return (RFCNBE_Bad);    /* Should be able to write that lot ... */
+
+    }
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Getting packet.\n");
+
+#endif
+
+    res_pkt.data = resp;
+    res_pkt.len = sizeof(resp);
+    res_pkt.next = NULL;
+
+    if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
+
+       return (RFCNBE_Bad);
+
+    }
+    /* Now analyze the packet ... */
+
+    switch (RFCNB_Pkt_Type(resp)) {
+
+    case RFCNB_SESSION_REJ:    /* Didnt like us ... too bad */
+
+       /* Why did we get rejected ? */
+
+       switch (CVAL(resp, RFCNB_Pkt_Error_Offset)) {
+
+       case 0x80:
+           RFCNB_errno = RFCNBE_CallRejNLOCN;
+           break;
+       case 0x81:
+           RFCNB_errno = RFCNBE_CallRejNLFCN;
+           break;
+       case 0x82:
+           RFCNB_errno = RFCNBE_CallRejCNNP;
+           break;
+       case 0x83:
+           RFCNB_errno = RFCNBE_CallRejInfRes;
+           break;
+       case 0x8F:
+           RFCNB_errno = RFCNBE_CallRejUnSpec;
+           break;
+       default:
+           RFCNB_errno = RFCNBE_ProtErr;
+           break;
+       }
+
+       return (RFCNBE_Bad);
+       break;
+
+    case RFCNB_SESSION_ACK:    /* Got what we wanted ...      */
+
+       return (0);
+       break;
+
+    case RFCNB_SESSION_RETARGET:       /* Go elsewhere                */
+
+       *redirect = TRUE;       /* Copy port and ip addr       */
+
+       memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
+       *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
+
+       return (0);
+       break;
+
+    default:                   /* A protocol error */
+
+       RFCNB_errno = RFCNBE_ProtErr;
+       return (RFCNBE_Bad);
+       break;
+    }
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb-util.h b/helpers/ntlm_auth/SMB/smbval/rfcnb-util.h
new file mode 100644 (file)
index 0000000..66e93ae
--- /dev/null
@@ -0,0 +1,50 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Utility Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+void RFCNB_CvtPad_Name(char *name1, char *name2);
+
+void RFCNB_AName_To_NBName(char *AName, char *NBName);
+
+void RFCNB_NBName_To_AName(char *NBName, char *AName);
+
+void RFCNB_Print_Hex(FILE * fd, struct RFCNB_Pkt *pkt, int Offset, int Len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Print_Pkt(FILE * fd, char *dirn, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP);
+
+int RFCNB_Close(int socket);
+
+int RFCNB_IP_Connect(struct in_addr Dest_IP, int port);
+
+int RFCNB_Session_Req(struct RFCNB_Con *con,
+    char *Called_Name,
+    char *Calling_Name,
+    BOOL * redirect,
+    struct in_addr *Dest_IP,
+    int *port);
diff --git a/helpers/ntlm_auth/SMB/smbval/rfcnb.h b/helpers/ntlm_auth/SMB/smbval/rfcnb.h
new file mode 100644 (file)
index 0000000..cd071f6
--- /dev/null
@@ -0,0 +1,55 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * RFCNB Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Error responses */
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "smblib-priv.h"
+
+/* Defines we need */
+
+#define RFCNB_Default_Port 139
+
+/* Definition of routines we define */
+
+void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port);
+
+int RFCNB_Send(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Recv(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Hangup(void *con_Handle);
+
+void *RFCNB_Listen();
+
+void RFCNB_Get_Error(char *buffer, int buf_len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
+
+int RFCNB_Set_Sock_NoDelay(void *con_Handle, BOOL yn);
diff --git a/helpers/ntlm_auth/SMB/smbval/session.c b/helpers/ntlm_auth/SMB/smbval/session.c
new file mode 100644 (file)
index 0000000..c69ced8
--- /dev/null
@@ -0,0 +1,388 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ * 
+ * Version 1.0
+ * Session Routines ...
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <malloc.h>
+#include <string.h>
+
+int RFCNB_errno = 0;
+int RFCNB_saved_errno = 0;
+#define RFCNB_ERRNO
+
+#include "std-includes.h"
+#include <netinet/tcp.h>
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+/* global data structures */
+
+static char *RFCNB_Error_Strings[] =
+{
+
+    "RFCNBE_OK: Routine completed successfully.",
+    "RFCNBE_NoSpace: No space available for a malloc call.",
+    "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+    "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+    "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+    "RFCNBE_ProtErr: A protocol error has occurred.",
+    "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+    "RFCNBE_BadHandle: Bad connection handle passed.",
+    "RFCNBE_BadSocket: Problems creating socket.",
+    "RFCNBE_ConnectFailed: Connection failed. See errno.",
+    "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+    "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+    "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+    "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+    "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+    "RFCNBE_BadParam: Bad parameters passed to a routine.",
+    "RFCNBE_Timeout: IO Operation timed out ..."
+
+};
+
+int RFCNB_Stats[RFCNB_MAX_STATS];
+
+void (*Prot_Print_Routine) () = NULL;  /* Pointer to print routine */
+
+/* Set up a session with a remote name. We are passed Called_Name as a
+ * string which we convert to a NetBIOS name, ie space terminated, up to
+ * 16 characters only if we need to. If Called_Address is not empty, then
+ * we use it to connect to the remote end, but put in Called_Name ... Called 
+ * Address can be a DNS based name, or a TCP/IP address ...
+ */
+
+void *
+RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+    int port)
+{
+    struct RFCNB_Con *con;
+    struct in_addr Dest_IP;
+    int Client;
+    BOOL redirect;
+    struct redirect_addr *redir_addr;
+    char *Service_Address;
+
+    /* Now, we really should look up the port in /etc/services ... */
+
+    if (port == 0)
+       port = RFCNB_Default_Port;
+
+    /* Create a connection structure first */
+
+    if ((con = (struct RFCNB_Con *) malloc(sizeof(struct RFCNB_Con))) == NULL) {       /* Error in size */
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (NULL);
+
+    }
+    con->fd = -0;              /* no descriptor yet */
+    con->rfc_errno = 0;                /* no error yet */
+    con->timeout = 0;          /* no timeout   */
+    con->redirects = 0;
+    con->redirect_list = NULL; /* Fix bug still in version 0.50 */
+
+    /* Resolve that name into an IP address */
+
+    Service_Address = Called_Name;
+    if (strcmp(Called_Address, "") != 0) {     /* If the Called Address = "" */
+       Service_Address = Called_Address;
+    }
+    if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) {   /* Error */
+
+       /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
+
+       return (NULL);
+
+    }
+    /* Now connect to the remote end */
+
+    redirect = TRUE;           /* Fudge this one so we go once through */
+
+    while (redirect) {         /* Connect and get session info etc */
+
+       redirect = FALSE;       /* Assume all OK */
+
+       /* Build the redirect info. First one is first addr called */
+       /* And tack it onto the list of addresses we called        */
+
+       if ((redir_addr = (struct redirect_addr *) malloc(sizeof(struct redirect_addr))) == NULL) {     /* Could not get space */
+
+           RFCNB_errno = RFCNBE_NoSpace;
+           RFCNB_saved_errno = errno;
+           return (NULL);
+
+       }
+       memcpy((char *) &(redir_addr->ip_addr), (char *) &Dest_IP, sizeof(Dest_IP));
+       redir_addr->port = port;
+       redir_addr->next = NULL;
+
+       if (con->redirect_list == NULL) {       /* Stick on head */
+
+           con->redirect_list = con->last_addr = redir_addr;
+
+       } else {
+
+           con->last_addr->next = redir_addr;
+           con->last_addr = redir_addr;
+
+       }
+
+       /* Now, make that connection */
+
+       if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) {   /* Error */
+
+           /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
+
+           return (NULL);
+
+       }
+       con->fd = Client;
+
+       /* Now send and handle the RFCNB session request              */
+       /* If we get a redirect, we will comeback with redirect true 
+        * and a new IP address in DEST_IP                            */
+
+       if ((errno = RFCNB_Session_Req(con,
+                   Called_Name,
+                   Calling_Name,
+                   &redirect, &Dest_IP, &port)) < 0) {
+
+           /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
+
+           return (NULL);
+
+       }
+       if (redirect) {
+
+           /* We have to close the connection, and then try again */
+
+           (con->redirects)++;
+
+           RFCNB_Close(con->fd);       /* Close it */
+
+       }
+    }
+
+    return (con);
+
+}
+
+/* We send a packet to the other end ... for the moment, we treat the 
+ * data as a series of pointers to blocks of data ... we should check the
+ * length ... */
+
+int
+RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    char *hdr;
+    int len;
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    pkt->next = udata;         /* The user data we want to send */
+
+    hdr = pkt->data;
+
+    /* Following crap is for portability across multiple UNIX machines */
+
+    *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
+    RFCNB_Put_Pkt_Len(hdr, Length);
+
+#ifdef RFCNB_DEBUG
+
+    fprintf(stderr, "Sending packet: ");
+
+#endif
+
+    if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+       /* No need to change RFCNB_errno as it was done by put_pkt ...     */
+
+       return (RFCNBE_Bad);    /* Should be able to write that lot ... */
+
+    }
+    /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (len);
+
+}
+
+/* We pick up a message from the internet ... We have to worry about 
+ * non-message packets ...                                           */
+
+int
+RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
+{
+    struct RFCNB_Pkt *pkt;
+    int ret_len;
+
+    if (con_Handle == NULL) {
+
+       RFCNB_errno = RFCNBE_BadHandle;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    /* Now get a packet from below. We allocate a header first */
+
+    /* Plug in the header and send the data */
+
+    pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+    if (pkt == NULL) {
+
+       RFCNB_errno = RFCNBE_NoSpace;
+       RFCNB_saved_errno = errno;
+       return (RFCNBE_Bad);
+
+    }
+    pkt->next = Data;          /* Plug in the data portion */
+
+    if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+#ifdef RFCNB_DEBUG
+       fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
+#endif
+
+       return (RFCNBE_Bad);
+
+    }
+    /* We should check that we go a message and not a keep alive */
+
+    pkt->next = NULL;
+
+    RFCNB_Free_Pkt(pkt);
+
+    return (ret_len);
+
+}
+
+/* We just disconnect from the other end, as there is nothing in the RFCNB */
+/* protocol that specifies any exchange as far as I can see                */
+
+int
+RFCNB_Hangup(struct RFCNB_Con *con_Handle)
+{
+
+    if (con_Handle != NULL) {
+       RFCNB_Close(con_Handle->fd);    /* Could this fail? */
+       free(con_Handle);
+    }
+    return 0;
+
+
+}
+
+/* Set TCP_NODELAY on the socket                                          */
+
+int
+RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
+{
+
+    return (setsockopt(con_Handle->fd, IPPROTO_TCP, TCP_NODELAY,
+           (char *) &yn, sizeof(yn)));
+
+}
+
+
+/* Listen for a connection on a port???, when                             */
+/* the connection comes in, we return with the connection                 */
+
+void *
+RFCNB_Listen()
+{
+    fprintf(stderr, "RFCNB_Listen NOT IMPLEMENTED as yet!\n");
+    return NULL;
+}
+
+/* Pick up the last error response as a string, hmmm, this routine should */
+/* have been different ...                                                */
+
+void
+RFCNB_Get_Error(char *buffer, int buf_len)
+{
+
+    if (RFCNB_saved_errno <= 0) {
+       sprintf(buffer, "%s", RFCNB_Error_Strings[RFCNB_errno]);
+    } else {
+       sprintf(buffer, "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
+           strerror(RFCNB_saved_errno));
+    }
+
+}
+
+/* Pick up the last error response and returns as a code                 */
+
+int
+RFCNB_Get_Last_Error()
+{
+
+    return (RFCNB_errno);
+
+}
+
+/* Pick up saved errno as well */
+
+int
+RFCNB_Get_Last_Errno()
+{
+
+    return (RFCNB_saved_errno);
+
+}
+
+/* Pick up the last error response and return in string ...             */
+
+void
+RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
+{
+
+    strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len);
+
+}
+
+/* Register a higher level protocol print routine */
+
+void
+RFCNB_Register_Print_Routine(void (*fn) ())
+{
+
+    Prot_Print_Routine = fn;
+
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/smbdes.c b/helpers/ntlm_auth/SMB/smbval/smbdes.c
new file mode 100644 (file)
index 0000000..a9ac145
--- /dev/null
@@ -0,0 +1,364 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * 
+ * a partial implementation of DES designed for use in the 
+ * SMB authentication protocol
+ * 
+ * Copyright (C) Andrew Tridgell 1997
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* NOTES: 
+ * 
+ * This code makes no attempt to be fast! In fact, it is a very
+ * slow implementation 
+ * 
+ * This code is NOT a complete DES implementation. It implements only
+ * the minimum necessary for SMB authentication, as used by all SMB
+ * products (including every copy of Microsoft Windows95 ever sold)
+ * 
+ * In particular, it can only do a unchained forward DES pass. This
+ * means it is not possible to use this code for encryption/decryption
+ * of data, instead it is only useful as a "hash" algorithm.
+ * 
+ * There is no entry point into this code that allows normal DES operation.
+ * 
+ * I believe this means that this code does not come under ITAR
+ * regulations but this is NOT a legal opinion. If you are concerned
+ * about the applicability of ITAR regulations to this code then you
+ * should confirm it for yourself (and maybe let me know if you come
+ * up with a different answer to the one above)
+ */
+
+
+
+static int perm1[56] =
+{57, 49, 41, 33, 25, 17, 9,
+    1, 58, 50, 42, 34, 26, 18,
+    10, 2, 59, 51, 43, 35, 27,
+    19, 11, 3, 60, 52, 44, 36,
+    63, 55, 47, 39, 31, 23, 15,
+    7, 62, 54, 46, 38, 30, 22,
+    14, 6, 61, 53, 45, 37, 29,
+    21, 13, 5, 28, 20, 12, 4};
+
+static int perm2[48] =
+{14, 17, 11, 24, 1, 5,
+    3, 28, 15, 6, 21, 10,
+    23, 19, 12, 4, 26, 8,
+    16, 7, 27, 20, 13, 2,
+    41, 52, 31, 37, 47, 55,
+    30, 40, 51, 45, 33, 48,
+    44, 49, 39, 56, 34, 53,
+    46, 42, 50, 36, 29, 32};
+
+static int perm3[64] =
+{58, 50, 42, 34, 26, 18, 10, 2,
+    60, 52, 44, 36, 28, 20, 12, 4,
+    62, 54, 46, 38, 30, 22, 14, 6,
+    64, 56, 48, 40, 32, 24, 16, 8,
+    57, 49, 41, 33, 25, 17, 9, 1,
+    59, 51, 43, 35, 27, 19, 11, 3,
+    61, 53, 45, 37, 29, 21, 13, 5,
+    63, 55, 47, 39, 31, 23, 15, 7};
+
+static int perm4[48] =
+{32, 1, 2, 3, 4, 5,
+    4, 5, 6, 7, 8, 9,
+    8, 9, 10, 11, 12, 13,
+    12, 13, 14, 15, 16, 17,
+    16, 17, 18, 19, 20, 21,
+    20, 21, 22, 23, 24, 25,
+    24, 25, 26, 27, 28, 29,
+    28, 29, 30, 31, 32, 1};
+
+static int perm5[32] =
+{16, 7, 20, 21,
+    29, 12, 28, 17,
+    1, 15, 23, 26,
+    5, 18, 31, 10,
+    2, 8, 24, 14,
+    32, 27, 3, 9,
+    19, 13, 30, 6,
+    22, 11, 4, 25};
+
+
+static int perm6[64] =
+{40, 8, 48, 16, 56, 24, 64, 32,
+    39, 7, 47, 15, 55, 23, 63, 31,
+    38, 6, 46, 14, 54, 22, 62, 30,
+    37, 5, 45, 13, 53, 21, 61, 29,
+    36, 4, 44, 12, 52, 20, 60, 28,
+    35, 3, 43, 11, 51, 19, 59, 27,
+    34, 2, 42, 10, 50, 18, 58, 26,
+    33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static int sc[16] =
+{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static int sbox[8][4][16] =
+{
+    {
+       {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+       {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+       {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+       {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+    {
+       {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+       {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+       {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+       {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+    {
+       {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+       {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+       {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+       {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+    {
+       {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+       {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+       {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+       {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+    {
+       {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+       {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+       {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+       {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+    {
+       {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+       {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+       {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+       {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+    {
+       {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+       {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+       {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+       {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+    {
+       {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+       {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+       {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+       {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void
+permute(char *out, char *in, int *p, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = in[p[i] - 1];
+}
+
+static void
+lshift(char *d, int count, int n)
+{
+    char out[64];
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = d[(i + count) % n];
+    for (i = 0; i < n; i++)
+       d[i] = out[i];
+}
+
+static void
+concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+    while (l1--)
+       *out++ = *in1++;
+    while (l2--)
+       *out++ = *in2++;
+}
+
+static void
+xor(char *out, char *in1, char *in2, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+       out[i] = in1[i] ^ in2[i];
+}
+
+static void
+dohash(char *out, char *in, char *key)
+{
+    int i, j, k;
+    char pk1[56];
+    char c[28];
+    char d[28];
+    char cd[56];
+    char ki[16][48];
+    char pd1[64];
+    char l[32], r[32];
+    char rl[64];
+
+    permute(pk1, key, perm1, 56);
+
+    for (i = 0; i < 28; i++)
+       c[i] = pk1[i];
+    for (i = 0; i < 28; i++)
+       d[i] = pk1[i + 28];
+
+    for (i = 0; i < 16; i++) {
+       lshift(c, sc[i], 28);
+       lshift(d, sc[i], 28);
+
+       concat(cd, c, d, 28, 28);
+       permute(ki[i], cd, perm2, 48);
+    }
+
+    permute(pd1, in, perm3, 64);
+
+    for (j = 0; j < 32; j++) {
+       l[j] = pd1[j];
+       r[j] = pd1[j + 32];
+    }
+
+    for (i = 0; i < 16; i++) {
+       char er[48];
+       char erk[48];
+       char b[8][6];
+       char cb[32];
+       char pcb[32];
+       char r2[32];
+
+       permute(er, r, perm4, 48);
+
+       xor(erk, er, ki[i], 48);
+
+       for (j = 0; j < 8; j++)
+           for (k = 0; k < 6; k++)
+               b[j][k] = erk[j * 6 + k];
+
+       for (j = 0; j < 8; j++) {
+           int m, n;
+           m = (b[j][0] << 1) | b[j][5];
+
+           n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
+
+           for (k = 0; k < 4; k++)
+               b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
+       }
+
+       for (j = 0; j < 8; j++)
+           for (k = 0; k < 4; k++)
+               cb[j * 4 + k] = b[j][k];
+       permute(pcb, cb, perm5, 32);
+
+       xor(r2, l, pcb, 32);
+
+       for (j = 0; j < 32; j++)
+           l[j] = r[j];
+
+       for (j = 0; j < 32; j++)
+           r[j] = r2[j];
+    }
+
+    concat(rl, r, l, 32, 32);
+
+    permute(out, rl, perm6, 64);
+}
+
+static void
+str_to_key(unsigned char *str, unsigned char *key)
+{
+    int i;
+
+    key[0] = str[0] >> 1;
+    key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
+    key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
+    key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
+    key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
+    key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
+    key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
+    key[7] = str[6] & 0x7F;
+    for (i = 0; i < 8; i++) {
+       key[i] = (key[i] << 1);
+    }
+}
+
+
+static void
+smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    int i;
+    char outb[64];
+    char inb[64];
+    char keyb[64];
+    unsigned char key2[8];
+
+    str_to_key(key, key2);
+
+    for (i = 0; i < 64; i++) {
+       inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+       keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+       outb[i] = 0;
+    }
+
+    dohash(outb, inb, keyb);
+
+    for (i = 0; i < 8; i++) {
+       out[i] = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+       if (outb[i])
+           out[i / 8] |= (1 << (7 - (i % 8)));
+    }
+}
+
+void
+E_P16(unsigned char *p14, unsigned char *p16)
+{
+    unsigned char sp8[8] =
+    {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+    smbhash(p16, sp8, p14);
+    smbhash(p16 + 8, sp8, p14 + 7);
+}
+
+void
+E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+    smbhash(p24, c8, p21);
+    smbhash(p24 + 8, c8, p21 + 7);
+    smbhash(p24 + 16, c8, p21 + 14);
+}
+
+void
+cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+
+    smbhash(buf, in, key);
+    smbhash(out, buf, key + 9);
+}
+
+void
+cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+    unsigned char buf[8];
+    static unsigned char key2[8];
+
+    smbhash(buf, in, key);
+    key2[0] = key[7];
+    smbhash(out, buf, key2);
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/smbdes.h b/helpers/ntlm_auth/SMB/smbval/smbdes.h
new file mode 100644 (file)
index 0000000..5a43114
--- /dev/null
@@ -0,0 +1,2 @@
+void E_P16(unsigned char *p14, unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
diff --git a/helpers/ntlm_auth/SMB/smbval/smbencrypt.c b/helpers/ntlm_auth/SMB/smbval/smbencrypt.c
new file mode 100644 (file)
index 0000000..4524b7f
--- /dev/null
@@ -0,0 +1,208 @@
+/* 
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1997
+ * Modified by Jeremy Allison 1995.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <ctype.h>
+//#include <arpa/inet.h>
+#include <dirent.h>
+#include <string.h>
+//#include <sys/vfs.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "smblib-priv.h"
+#include "md4.h"
+#include "smbdes.h"
+#define uchar unsigned char
+extern int DEBUGLEVEL;
+
+#include "byteorder.h"
+
+char *StrnCpy(char *dest, char *src, int n);
+void strupper(char *s);
+
+/*
+ * This implements the X/Open SMB password encryption
+ * It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+ * encrypted password into p24 */
+void
+SMBencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p14[15], p21[21];
+
+    memset(p21, '\0', 21);
+    memset(p14, '\0', 14);
+    StrnCpy((char *) p14, (char *) passwd, 14);
+
+    strupper((char *) p14);
+    E_P16(p14, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(int16 * str)
+{
+    int len = 0;
+    while (*str++ != 0)
+       len++;
+    return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(int16 * dst, uchar * src, int len)
+{
+    int i;
+    int16 val;
+
+    for (i = 0; i < len; i++) {
+       val = *src;
+       SSVAL(dst, 0, val);
+       dst++;
+       src++;
+       if (val == 0)
+           break;
+    }
+    return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(uchar * passwd, uchar * p16)
+{
+    int len;
+    int16 wpwd[129];
+
+    /* Password cannot be longer than 128 characters */
+    len = strlen((char *) passwd);
+    if (len > 128)
+       len = 128;
+    /* Password must be converted to NT unicode */
+    _my_mbstowcs(wpwd, passwd, len);
+    wpwd[len] = 0;             /* Ensure string is null terminated */
+    /* Calculate length in bytes */
+    len = _my_wcslen(wpwd) * sizeof(int16);
+
+    mdfour(p16, (unsigned char *) wpwd, len);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24)
+{
+    uchar p21[21];
+
+    memset(p21, '\0', 21);
+
+    E_md4hash(passwd, p21);
+    E_P24(p21, c8, p24);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+
+void
+nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+    char passwd[130];
+    StrnCpy(passwd, pwd, sizeof(passwd) - 1);
+
+    /* Calculate the MD4 hash (NT compatible) of the password */
+    memset(nt_p16, '\0', 16);
+    E_md4hash((uchar *) passwd, (uchar *) nt_p16);
+
+    /* Mangle the passwords into Lanman format */
+    passwd[14] = '\0';
+    strupper(passwd);
+
+    /* Calculate the SMB (lanman) hash functions of the password */
+
+    memset(p16, '\0', 16);
+    E_P16((uchar *) passwd, (uchar *) p16);
+
+    /* clear out local copy of user's password (just being paranoid). */
+    bzero(passwd, sizeof(passwd));
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *
+StrnCpy(char *dest, char *src, int n)
+{
+    char *d = dest;
+    if (!dest)
+       return (NULL);
+    if (!src) {
+       *dest = 0;
+       return (dest);
+    }
+    while (n-- && (*d++ = *src++));
+    *d = 0;
+    return (dest);
+}
+
+void
+strupper(char *s)
+{
+    while (*s) {
+       /*
+        * #if !defined(KANJI_WIN95_COMPATIBILITY)
+        * if(lp_client_code_page() == KANJI_CODEPAGE)
+        * {
+        * 
+        * if (is_shift_jis (*s))
+        * {
+        * if (is_sj_lower (s[0], s[1]))
+        * s[1] = sj_toupper2 (s[1]);
+        * s += 2;
+        * }
+        * else if (is_kana (*s))
+        * {
+        * s++;
+        * }
+        * else
+        * {
+        * if (islower(*s))                           
+        * *s = toupper(*s);
+        * s++;
+        * }
+        * }
+        * else
+        * #endif *//* KANJI_WIN95_COMPATIBILITY */
+       {
+           if (islower(*s))
+               *s = toupper(*s);
+           s++;
+       }
+    }
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/smbencrypt.h b/helpers/ntlm_auth/SMB/smbval/smbencrypt.h
new file mode 100644 (file)
index 0000000..9dd72a9
--- /dev/null
@@ -0,0 +1 @@
+void SMBencrypt(uchar * passwd, uchar * c8, uchar * p24);
diff --git a/helpers/ntlm_auth/SMB/smbval/smblib-common.h b/helpers/ntlm_auth/SMB/smbval/smblib-common.h
new file mode 100644 (file)
index 0000000..f2a4bb2
--- /dev/null
@@ -0,0 +1,189 @@
+#ifndef __SMBLIB_COMMON_H__
+#define __SMBLIB_COMMON_H__
+
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Common Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* To get the error class we want the first 8 bits */
+/* Because we just grab 4bytes from the SMB header, we have to re-order */
+/* here, but it makes the NtStatus part easier in future                */
+
+#define SMBlib_Error_Class(p) (p & 0x000000FF)
+
+/* To get the error code, we want the bottom 16 bits */
+
+#define SMBlib_Error_Code(p) (((unsigned int)p & 0xFFFF0000) >>16)
+
+/* Error CLASS codes and etc ... */
+
+#define SMBC_SUCCESS        0
+#define SMBC_ERRDOS         0x01
+#define SMBC_ERRSRV         0x02
+#define SMBC_ERRHRD         0x03
+#define SMBC_ERRCMD         0xFF
+
+/* Success error codes    */
+
+#define SMBS_BUFFERED       0x54
+#define SMBS_LOGGED         0x55
+#define SMBS_DISPLAYED      0x56
+
+/* ERRDOS Error codes     */
+
+#define SMBD_badfunc        0x01
+#define SMBD_badfile        0x02
+#define SMBD_badpath        0x03
+#define SMBD_nofids         0x04
+#define SMBD_noaccess       0x05
+#define SMBD_badfid         0x06
+#define SMBD_badmcb         0x07
+#define SMBD_nomem          0x08
+#define SMBD_badmem         0x09
+#define SMBD_badenv         0x0A
+#define SMBD_badformat      0x0B
+#define SMBD_badaccess      0x0C
+#define SMBD_baddata        0x0D
+#define SMBD_reserved       0x0E
+#define SMBD_baddrive       0x0F
+#define SMBD_remcd          0x10
+#define SMBD_diffdevice     0x11
+#define SMBD_nofiles        0x12
+#define SMBD_badshare       0x20
+#define SMBD_errlock        0x21
+#define SMBD_filexists      0x50
+
+/* Server errors ... */
+
+#define SMBV_error          0x01       /* Generic error */
+#define SMBV_badpw          0x02
+#define SMBV_badtype        0x03
+#define SMBV_access         0x04
+#define SMBV_invnid         0x05
+#define SMBV_invnetname     0x06
+#define SMBV_invdevice      0x07
+#define SMBV_qfull          0x31
+#define SMBV_qtoobig        0x32
+#define SMBV_qeof           0x33
+#define SMBV_invpfid        0x34
+#define SMBV_paused         0x51
+#define SMBV_msgoff         0x52
+#define SMBV_noroom         0x53
+#define SMBV_rmuns          0x57
+#define SMBV_nosupport      0xFFFF
+
+/* Hardware error codes ... */
+
+#define SMBH_nowrite        0x13
+#define SMBH_badunit        0x14
+#define SMBH_notready       0x15
+#define SMBH_badcmd         0x16
+#define SMBH_data           0x17
+#define SMBH_badreq         0x18
+#define SMBH_seek           0x19
+#define SMBH_badmedia       0x1A
+#define SMBH_badsector      0x1B
+#define SMBH_nopaper        0x1C
+#define SMBH_write          0x1D
+#define SMBH_read           0x1E
+#define SMBH_general        0x1F
+#define SMBH_badshare       0x20
+
+/* Access mode defines ... */
+
+#define SMB_AMODE_WTRU      0x4000
+#define SMB_AMODE_NOCACHE   0x1000
+#define SMB_AMODE_COMPAT    0x0000
+#define SMB_AMODE_DENYRWX   0x0010
+#define SMB_AMODE_DENYW     0x0020
+#define SMB_AMODE_DENYRX    0x0030
+#define SMB_AMODE_DENYNONE  0x0040
+#define SMB_AMODE_OPENR     0x0000
+#define SMB_AMODE_OPENW     0x0001
+#define SMB_AMODE_OPENRW    0x0002
+#define SMB_AMODE_OPENX     0x0003
+#define SMB_AMODE_FCBOPEN   0x00FF
+#define SMB_AMODE_LOCUNKN   0x0000
+#define SMB_AMODE_LOCMSEQ   0x0100
+#define SMB_AMODE_LOCMRAN   0x0200
+#define SMB_AMODE_LOCRAL    0x0300
+
+/* File attribute encoding ... */
+
+#define SMB_FA_ORD          0x00
+#define SMB_FA_ROF          0x01
+#define SMB_FA_HID          0x02
+#define SMB_FA_SYS          0x04
+#define SMB_FA_VOL          0x08
+#define SMB_FA_DIR          0x10
+#define SMB_FA_ARC          0x20
+
+/* Define the protocol types ... */
+
+#define SMB_P_Unknown      -1  /* Hmmm, is this smart? */
+#define SMB_P_Core         0
+#define SMB_P_CorePlus     1
+#define SMB_P_DOSLanMan1   2
+#define SMB_P_LanMan1      3
+#define SMB_P_DOSLanMan2   4
+#define SMB_P_LanMan2      5
+#define SMB_P_DOSLanMan2_1 6
+#define SMB_P_LanMan2_1    7
+#define SMB_P_NT1          8
+
+/* SMBlib return codes */
+/* We want something that indicates whether or not the return code was a   */
+/* remote error, a local error in SMBlib or returned from lower layer ...  */
+/* Wonder if this will work ...                                            */
+/* SMBlibE_Remote = 1 indicates remote error                               */
+/* SMBlibE_ values < 0 indicate local error with more info available       */
+/* SMBlibE_ values >1 indicate local from SMBlib code errors?              */
+
+#define SMBlibE_Success 0
+#define SMBlibE_Remote  1      /* Remote error, get more info from con        */
+#define SMBlibE_BAD     -1
+#define SMBlibE_LowerLayer 2   /* Lower layer error                           */
+#define SMBlibE_NotImpl 3      /* Function not yet implemented                */
+#define SMBlibE_ProtLow 4      /* Protocol negotiated does not support req    */
+#define SMBlibE_NoSpace 5      /* No space to allocate a structure            */
+#define SMBlibE_BadParam 6     /* Bad parameters                              */
+#define SMBlibE_NegNoProt 7    /* None of our protocols was liked             */
+#define SMBlibE_SendFailed 8   /* Sending an SMB failed                       */
+#define SMBlibE_RecvFailed 9   /* Receiving an SMB failed                     */
+#define SMBlibE_GuestOnly 10   /* Logged in as guest                          */
+#define SMBlibE_CallFailed 11  /* Call remote end failed                     */
+#define SMBlibE_ProtUnknown 12 /* Protocol unknown                          */
+#define SMBlibE_NoSuchMsg  13  /* Keep this up to date                       */
+
+typedef struct {               /* A structure for a Dirent */
+
+    unsigned char resume_key[21];      /* Don't touch this          */
+    unsigned char file_attributes;     /* Attributes of file        */
+    unsigned int date_time;    /* date and time of last mod */
+    unsigned int size;
+    char filename[13];         /* The name of the file      */
+
+} SMB_CP_dirent;
+
+#endif /* __SMBLIB_COMMON_H__ */
diff --git a/helpers/ntlm_auth/SMB/smbval/smblib-priv.h b/helpers/ntlm_auth/SMB/smbval/smblib-priv.h
new file mode 100644 (file)
index 0000000..412dcca
--- /dev/null
@@ -0,0 +1,655 @@
+#ifndef __SMBLIB_PRIV_H__
+#define __SMBLIB_PRIV_H__
+
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib private Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-defines.h"
+#include "smblib-common.h"
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#include "byteorder.h"         /* Hmmm ... hot good */
+
+#define max(a,b) (a < b ? b : a)
+
+#define SMB_DEF_IDF 0x424D53FF /* "\377SMB" */
+
+/* Core protocol commands */
+
+#define SMBmkdir      0x00     /* create directory */
+#define SMBrmdir      0x01     /* delete directory */
+#define SMBopen       0x02     /* open file */
+#define SMBcreate     0x03     /* create file */
+#define SMBclose      0x04     /* close file */
+#define SMBflush      0x05     /* flush file */
+#define SMBunlink     0x06     /* delete file */
+#define SMBmv         0x07     /* rename file */
+#define SMBgetatr     0x08     /* get file attributes */
+#define SMBsetatr     0x09     /* set file attributes */
+#define SMBread       0x0A     /* read from file */
+#define SMBwrite      0x0B     /* write to file */
+#define SMBlock       0x0C     /* lock byte range */
+#define SMBunlock     0x0D     /* unlock byte range */
+#define SMBctemp      0x0E     /* create temporary file */
+#define SMBmknew      0x0F     /* make new file */
+#define SMBchkpth     0x10     /* check directory path */
+#define SMBexit       0x11     /* process exit */
+#define SMBlseek      0x12     /* seek */
+#define SMBtcon       0x70     /* tree connect */
+#define SMBtdis       0x71     /* tree disconnect */
+#define SMBnegprot    0x72     /* negotiate protocol */
+#define SMBdskattr    0x80     /* get disk attributes */
+#define SMBsearch     0x81     /* search directory */
+#define SMBsplopen    0xC0     /* open print spool file */
+#define SMBsplwr      0xC1     /* write to print spool file */
+#define SMBsplclose   0xC2     /* close print spool file */
+#define SMBsplretq    0xC3     /* return print queue */
+#define SMBsends      0xD0     /* send single block message */
+#define SMBsendb      0xD1     /* send broadcast message */
+#define SMBfwdname    0xD2     /* forward user name */
+#define SMBcancelf    0xD3     /* cancel forward */
+#define SMBgetmac     0xD4     /* get machine name */
+#define SMBsendstrt   0xD5     /* send start of multi-block message */
+#define SMBsendend    0xD6     /* send end of multi-block message */
+#define SMBsendtxt    0xD7     /* send text of multi-block message */
+
+/* CorePlus protocol                                        */
+
+#define SMBlockread   0x13     /* Lock a range and read it */
+#define SMBwriteunlock 0x14    /* Unlock a range and then write */
+#define SMBreadbraw   0x1a     /* read a block of data without smb header ohead */
+#define SMBwritebraw  0x1d     /* write a block of data without smb header ohead */
+#define SMBwritec     0x20     /* secondary write request */
+#define SMBwriteclose 0x2c     /* write a file and then close it */
+
+/* DOS Extended Protocol                                    */
+
+#define SMBreadBraw      0x1A  /* read block raw */
+#define SMBreadBmpx      0x1B  /* read block multiplexed */
+#define SMBreadBs        0x1C  /* read block (secondary response) */
+#define SMBwriteBraw     0x1D  /* write block raw */
+#define SMBwriteBmpx     0x1E  /* write block multiplexed */
+#define SMBwriteBs       0x1F  /* write block (secondary request) */
+#define SMBwriteC        0x20  /* write complete response */
+#define SMBsetattrE      0x22  /* set file attributes expanded */
+#define SMBgetattrE      0x23  /* get file attributes expanded */
+#define SMBlockingX      0x24  /* lock/unlock byte ranges and X */
+#define SMBtrans         0x25  /* transaction - name, bytes in/out */
+#define SMBtranss        0x26  /* transaction (secondary request/response) */
+#define SMBioctl         0x27  /* IOCTL */
+#define SMBioctls        0x28  /* IOCTL  (secondary request/response) */
+#define SMBcopy          0x29  /* copy */
+#define SMBmove          0x2A  /* move */
+#define SMBecho          0x2B  /* echo */
+#define SMBopenX         0x2D  /* open and X */
+#define SMBreadX         0x2E  /* read and X */
+#define SMBwriteX        0x2F  /* write and X */
+#define SMBsesssetupX    0x73  /* Session Set Up & X (including User Logon) */
+#define SMBtconX         0x75  /* tree connect and X */
+#define SMBffirst        0x82  /* find first */
+#define SMBfunique       0x83  /* find unique */
+#define SMBfclose        0x84  /* find close */
+#define SMBinvalid       0xFE  /* invalid command */
+
+/* Any more ? */
+
+#define SMBdatablockID     0x01        /* A data block identifier */
+#define SMBdialectID       0x02        /* A dialect id            */
+#define SMBpathnameID      0x03        /* A pathname ID           */
+#define SMBasciiID         0x04        /* An ascii string ID      */
+#define SMBvariableblockID 0x05        /* A variable block ID     */
+
+/* some other defines we need */
+
+/* Flags defines ... */
+
+#define SMB_FLG2_NON_DOS    0x01       /* We know non dos names             */
+#define SMB_FLG2_EXT_ATR    0x02       /* We know about Extended Attributes */
+#define SMB_FLG2_LNG_NAM    0x04       /* Long names ?                      */
+
+typedef unsigned short WORD;
+typedef unsigned short UWORD;
+typedef unsigned int ULONG;
+typedef unsigned char BYTE;
+typedef unsigned char UCHAR;
+
+/* Some macros to allow access to actual packet data so that we */
+/* can change the underlying representation of packets.         */
+/*                                                              */
+/* The current formats vying for attention are a fragment       */
+/* approach where the SMB header is a fragment linked to the    */
+/* data portion with the transport protocol (rfcnb or whatever) */
+/* being linked on the front.                                   */
+/*                                                              */
+/* The other approach is where the whole packet is one array    */
+/* of bytes with space allowed on the front for the packet      */
+/* headers.                                                     */
+
+#define SMB_Hdr(p) (char *)(p -> data)
+
+/* SMB Hdr def for File Sharing Protocol? From MS and Intel,    */
+/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also  */
+/* applies to LANMAN1.0 as well as the Core Protocol            */
+/* The spec states that wct and bcc must be present, even if 0  */
+
+/* We define these as offsets into a char SMB[] array for the   */
+/* sake of portability                                          */
+
+/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */
+/* the data that follows in the SMB packet, so the code will have to   */
+/* take that into account.                                             */
+
+#define SMB_hdr_idf_offset    0        /* 0xFF,'SMB' 0-3 */
+#define SMB_hdr_com_offset    4        /* BYTE       4   */
+#define SMB_hdr_rcls_offset   5        /* BYTE       5   */
+#define SMB_hdr_reh_offset    6        /* BYTE       6   */
+#define SMB_hdr_err_offset    7        /* WORD       7   */
+#define SMB_hdr_reb_offset    9        /* BYTE       9   */
+#define SMB_hdr_flg_offset    9        /* same as reb ... */
+#define SMB_hdr_res_offset    10       /* 7 WORDs    10  */
+#define SMB_hdr_res0_offset   10       /* WORD       10  */
+#define SMB_hdr_flg2_offset   10       /* WORD           */
+#define SMB_hdr_res1_offset   12       /* WORD       12  */
+#define SMB_hdr_res2_offset   14
+#define SMB_hdr_res3_offset   16
+#define SMB_hdr_res4_offset   18
+#define SMB_hdr_res5_offset   20
+#define SMB_hdr_res6_offset   22
+#define SMB_hdr_tid_offset    24
+#define SMB_hdr_pid_offset    26
+#define SMB_hdr_uid_offset    28
+#define SMB_hdr_mid_offset    30
+#define SMB_hdr_wct_offset    32
+
+#define SMB_hdr_len           33       /* 33 byte header?      */
+
+#define SMB_hdr_axc_offset    33       /* AndX Command         */
+#define SMB_hdr_axr_offset    34       /* AndX Reserved        */
+#define SMB_hdr_axo_offset    35       /* Offset from start to WCT of AndX cmd */
+
+/* Format of the Negotiate Protocol SMB */
+
+#define SMB_negp_bcc_offset   33
+#define SMB_negp_buf_offset   35       /* Where the buffer starts   */
+#define SMB_negp_len          35       /* plus the data             */
+
+/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */
+/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */
+/* for NT LM 0.12                                                    */
+
+#define SMB_negrCP_idx_offset   33     /* Response to the neg req */
+#define SMB_negrCP_bcc_offset   35
+#define SMB_negrLM_idx_offset   33     /* dialect index           */
+#define SMB_negrLM_sec_offset   35     /* Security mode           */
+#define SMB_sec_user_mask       0x01   /* 0 = share, 1 = user     */
+#define SMB_sec_encrypt_mask    0x02   /* pick out encrypt        */
+#define SMB_negrLM_mbs_offset   37     /* max buffer size         */
+#define SMB_negrLM_mmc_offset   39     /* max mpx count           */
+#define SMB_negrLM_mnv_offset   41     /* max number of VCs       */
+#define SMB_negrLM_rm_offset    43     /* raw mode support bit vec */
+#define SMB_read_raw_mask       0x01
+#define SMB_write_raw_mask      0x02
+#define SMB_negrLM_sk_offset    45     /* session key, 32 bits    */
+#define SMB_negrLM_st_offset    49     /* Current server time     */
+#define SMB_negrLM_sd_offset    51     /* Current server date     */
+#define SMB_negrLM_stz_offset   53     /* Server Time Zone        */
+#define SMB_negrLM_ekl_offset   55     /* encryption key length   */
+#define SMB_negrLM_res_offset   57     /* reserved                */
+#define SMB_negrLM_bcc_offset   59     /* bcc                     */
+#define SMB_negrLM_len          61     /* 61 bytes ?              */
+#define SMB_negrLM_buf_offset   61     /* Where the fun begins    */
+
+#define SMB_negrNTLM_idx_offset 33     /* Selected protocol       */
+#define SMB_negrNTLM_sec_offset 35     /* Security more           */
+#define SMB_negrNTLM_mmc_offset 36     /* Different format above  */
+#define SMB_negrNTLM_mnv_offset 38     /* Max VCs                 */
+#define SMB_negrNTLM_mbs_offset 40     /* MBS now a long          */
+#define SMB_negrNTLM_mrs_offset 44     /* Max raw size            */
+#define SMB_negrNTLM_sk_offset  48     /* Session Key             */
+#define SMB_negrNTLM_cap_offset 52     /* Capabilities            */
+#define SMB_negrNTLM_stl_offset 56     /* Server time low         */
+#define SMB_negrNTLM_sth_offset 60     /* Server time high        */
+#define SMB_negrNTLM_stz_offset 64     /* Server time zone        */
+#define SMB_negrNTLM_ekl_offset 66     /* Encrypt key len         */
+#define SMB_negrNTLM_bcc_offset 67     /* Bcc                     */
+#define SMB_negrNTLM_len        69
+#define SMB_negrNTLM_buf_offset 69
+
+/* Offsets related to Tree Connect                                      */
+
+#define SMB_tcon_bcc_offset     33
+#define SMB_tcon_buf_offset     35     /* where the data is for tcon */
+#define SMB_tcon_len            35     /* plus the data              */
+
+#define SMB_tconr_mbs_offset    33     /* max buffer size         */
+#define SMB_tconr_tid_offset    35     /* returned tree id        */
+#define SMB_tconr_bcc_offset    37
+#define SMB_tconr_len           39
+
+#define SMB_tconx_axc_offset    33     /* And X Command                */
+#define SMB_tconx_axr_offset    34     /* reserved                     */
+#define SMB_tconx_axo_offset    35     /* Next command offset          */
+#define SMB_tconx_flg_offset    37     /* Flags, bit0=1 means disc TID */
+#define SMB_tconx_pwl_offset    39     /* Password length              */
+#define SMB_tconx_bcc_offset    41     /* bcc                          */
+#define SMB_tconx_buf_offset    43     /* buffer                       */
+#define SMB_tconx_len           43     /* up to data ...               */
+
+#define SMB_tconxr_axc_offset   33     /* Where the AndX Command is    */
+#define SMB_tconxr_axr_offset   34     /* Reserved                     */
+#define SMB_tconxr_axo_offset   35     /* AndX offset location         */
+
+/* Offsets related to tree_disconnect                                  */
+
+#define SMB_tdis_bcc_offset     33     /* bcc                     */
+#define SMB_tdis_len            35     /* total len               */
+
+#define SMB_tdisr_bcc_offset    33     /* bcc                     */
+#define SMB_tdisr_len           35
+
+/* Offsets related to Open Request                                     */
+
+#define SMB_open_mod_offset     33     /* Mode to open with       */
+#define SMB_open_atr_offset     35     /* Attributes of file      */
+#define SMB_open_bcc_offset     37     /* bcc                     */
+#define SMB_open_buf_offset     39     /* File name               */
+#define SMB_open_len            39     /* Plus the file name      */
+
+#define SMB_openx_axc_offset    33     /* Next command            */
+#define SMB_openx_axr_offset    34     /* Reserved                */
+#define SMB_openx_axo_offset    35     /* offset of next wct      */
+#define SMB_openx_flg_offset    37     /* Flags, bit0 = need more info */
+                                         /* bit1 = exclusive oplock */
+                                         /* bit2 = batch oplock     */
+#define SMB_openx_mod_offset    39     /* mode to open with       */
+#define SMB_openx_atr_offset    41     /* search attributes       */
+#define SMB_openx_fat_offset    43     /* File attributes         */
+#define SMB_openx_tim_offset    45     /* time and date of creat  */
+#define SMB_openx_ofn_offset    49     /* Open function           */
+#define SMB_openx_als_offset    51     /* Space to allocate on    */
+#define SMB_openx_res_offset    55     /* reserved                */
+#define SMB_openx_bcc_offset    63     /* bcc                     */
+#define SMB_openx_buf_offset    65     /* Where file name goes    */
+#define SMB_openx_len           65
+
+#define SMB_openr_fid_offset    33     /* FID returned            */
+#define SMB_openr_atr_offset    35     /* Attributes opened with  */
+#define SMB_openr_tim_offset    37     /* Last mod time of file   */
+#define SMB_openr_fsz_offset    41     /* File size 4 bytes       */
+#define SMB_openr_acc_offset    45     /* Access allowed          */
+#define SMB_openr_bcc_offset    47
+#define SMB_openr_len           49
+
+#define SMB_openxr_axc_offset   33     /* And X command           */
+#define SMB_openxr_axr_offset   34     /* reserved                */
+#define SMB_openxr_axo_offset   35     /* offset to next command  */
+#define SMB_openxr_fid_offset   37     /* FID returned            */
+#define SMB_openxr_fat_offset   39     /* File attributes returned */
+#define SMB_openxr_tim_offset   41     /* File creation date etc  */
+#define SMB_openxr_fsz_offset   45     /* Size of file            */
+#define SMB_openxr_acc_offset   49     /* Access granted          */
+
+#define SMB_clos_fid_offset     33     /* FID to close            */
+#define SMB_clos_tim_offset     35     /* Last mod time           */
+#define SMB_clos_bcc_offset     39     /* bcc                     */
+#define SMB_clos_len            41
+
+/* Offsets related to Write requests                                 */
+
+#define SMB_write_fid_offset    33     /* FID to write            */
+#define SMB_write_cnt_offset    35     /* bytes to write          */
+#define SMB_write_ofs_offset    37     /* location to write to    */
+#define SMB_write_clf_offset    41     /* advisory count left     */
+#define SMB_write_bcc_offset    43     /* bcc = data bytes + 3    */
+#define SMB_write_buf_offset    45     /* Data=0x01, len, data    */
+#define SMB_write_len           45     /* plus the data ...       */
+
+#define SMB_writr_cnt_offset    33     /* Count of bytes written  */
+#define SMB_writr_bcc_offset    35     /* bcc                     */
+#define SMB_writr_len           37
+
+/* Offsets related to read requests */
+
+#define SMB_read_fid_offset     33     /* FID of file to read     */
+#define SMB_read_cnt_offset     35     /* count of words to read  */
+#define SMB_read_ofs_offset     37     /* Where to read from      */
+#define SMB_read_clf_offset     41     /* Advisory count to go    */
+#define SMB_read_bcc_offset     43
+#define SMB_read_len            45
+
+#define SMB_readr_cnt_offset    33     /* Count of bytes returned */
+#define SMB_readr_res_offset    35     /* 4 shorts reserved, 8 bytes */
+#define SMB_readr_bcc_offset    43     /* bcc                     */
+#define SMB_readr_bff_offset    45     /* buffer format char = 0x01 */
+#define SMB_readr_len_offset    46     /* buffer len              */
+#define SMB_readr_len           45     /* length of the readr before data */
+
+/* Offsets for Create file                                           */
+
+#define SMB_creat_atr_offset    33     /* Attributes of new file ... */
+#define SMB_creat_tim_offset    35     /* Time of creation           */
+#define SMB_creat_dat_offset    37     /* 4004BCE :-)                */
+#define SMB_creat_bcc_offset    39     /* bcc                        */
+#define SMB_creat_buf_offset    41
+#define SMB_creat_len           41     /* Before the data            */
+
+#define SMB_creatr_fid_offset   33     /* FID of created file        */
+
+/* Offsets for Delete file                                           */
+
+#define SMB_delet_sat_offset    33     /* search attribites          */
+#define SMB_delet_bcc_offset    35     /* bcc                        */
+#define SMB_delet_buf_offset    37
+#define SMB_delet_len           37
+
+/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols    */
+
+#define SMB_ssetpLM_mbs_offset  37     /* Max buffer Size, allow for AndX */
+#define SMB_ssetpLM_mmc_offset  39     /* max multiplex count             */
+#define SMB_ssetpLM_vcn_offset  41     /* VC number if new VC             */
+#define SMB_ssetpLM_snk_offset  43     /* Session Key                     */
+#define SMB_ssetpLM_pwl_offset  47     /* password length                 */
+#define SMB_ssetpLM_res_offset  49     /* reserved                        */
+#define SMB_ssetpLM_bcc_offset  53     /* bcc                             */
+#define SMB_ssetpLM_len         55     /* before data ...                 */
+#define SMB_ssetpLM_buf_offset  55
+
+#define SMB_ssetpNTLM_mbs_offset 37    /* Max Buffer Size for NT LM 0.12  */
+                                         /* and above                       */
+#define SMB_ssetpNTLM_mmc_offset 39    /* Max Multiplex count             */
+#define SMB_ssetpNTLM_vcn_offset 41    /* VC Number                       */
+#define SMB_ssetpNTLM_snk_offset 43    /* Session key                     */
+#define SMB_ssetpNTLM_cipl_offset 47   /* Case Insensitive PW Len         */
+#define SMB_ssetpNTLM_cspl_offset 49   /* Unicode pw len                  */
+#define SMB_ssetpNTLM_res_offset 51    /* reserved                        */
+#define SMB_ssetpNTLM_cap_offset 55    /* server capabilities             */
+#define SMB_ssetpNTLM_bcc_offset 59    /* bcc                             */
+#define SMB_ssetpNTLM_len        61    /* before data                     */
+#define SMB_ssetpNTLM_buf_offset 61
+
+#define SMB_ssetpr_axo_offset  35      /* Offset of next response ...    */
+#define SMB_ssetpr_act_offset  37      /* action, bit 0 = 1 => guest     */
+#define SMB_ssetpr_bcc_offset  39      /* bcc                            */
+#define SMB_ssetpr_buf_offset  41      /* Native OS etc                  */
+
+/* Offsets for SMB create directory                                         */
+
+#define SMB_creatdir_bcc_offset 33     /* only a bcc here                */
+#define SMB_creatdir_buf_offset 35     /* Where things start             */
+#define SMB_creatdir_len        35
+
+/* Offsets for SMB delete directory                                         */
+
+#define SMB_deletdir_bcc_offset 33     /* only a bcc here                */
+#define SMB_deletdir_buf_offset 35     /* where things start             */
+#define SMB_deletdir_len        35
+
+/* Offsets for SMB check directory                                          */
+
+#define SMB_checkdir_bcc_offset 33     /* Only a bcc here                */
+#define SMB_checkdir_buf_offset 35     /* where things start             */
+#define SMB_checkdir_len        35
+
+/* Offsets for SMB search                                                   */
+
+#define SMB_search_mdc_offset   33     /* Max Dir ents to return         */
+#define SMB_search_atr_offset   35     /* Search attributes              */
+#define SMB_search_bcc_offset   37     /* bcc                            */
+#define SMB_search_buf_offset   39     /* where the action is            */
+#define SMB_search_len          39
+
+#define SMB_searchr_dec_offset  33     /* Dir ents returned              */
+#define SMB_searchr_bcc_offset  35     /* bcc                            */
+#define SMB_searchr_buf_offset  37     /* Where the action starts        */
+#define SMB_searchr_len         37     /* before the dir ents            */
+
+#define SMB_searchr_dirent_len  43     /* 53 bytes                       */
+
+/* Defines for SMB transact and transact2 calls                             */
+
+#define SMB_trans_tpc_offset    33     /* Total param count              */
+#define SMB_trans_tdc_offset    35     /* total Data count               */
+#define SMB_trans_mpc_offset    37     /* Max params bytes to return     */
+#define SMB_trans_mdc_offset    39     /* Max data bytes to return       */
+#define SMB_trans_msc_offset    41     /* Max setup words to return      */
+#define SMB_trans_rs1_offset    42     /* Reserved byte                  */
+#define SMB_trans_flg_offset    43     /* flags                          */
+#define SMB_trans_tmo_offset    45     /* Timeout, long                  */
+#define SMB_trans_rs2_offset    49     /* Next reserved                  */
+#define SMB_trans_pbc_offset    51     /* Param Byte count in buf        */
+#define SMB_trans_pbo_offset    53     /* Offset to param bytes          */
+#define SMB_trans_dbc_offset    55     /* Data byte count in buf         */
+#define SMB_trans_dbo_offset    57     /* Data byte offset               */
+#define SMB_trans_suc_offset    59     /* Setup count - byte             */
+#define SMB_trans_rs3_offset    60     /* Reserved to pad ...            */
+#define SMB_trans_len           61     /* Up to setup, still need bcc    */
+
+#define SMB_transr_tpc_offset   33     /* Total param bytes returned     */
+#define SMB_transr_tdc_offset   35
+#define SMB_transr_rs1_offset   37
+#define SMB_transr_pbc_offset   39
+#define SMB_transr_pbo_offset   41
+#define SMB_transr_pdi_offset   43     /* parameter displacement         */
+#define SMB_transr_dbc_offset   45
+#define SMB_transr_dbo_offset   47
+#define SMB_transr_ddi_offset   49
+#define SMB_transr_suc_offset   51
+#define SMB_transr_rs2_offset   52
+#define SMB_transr_len          53
+
+/* Bit masks for SMB Capabilities ...                       */
+
+#define SMB_cap_raw_mode         0x0001
+#define SMB_cap_mpx_mode         0x0002
+#define SMB_cap_unicode          0x0004
+#define SMB_cap_large_files      0x0008
+#define SMB_cap_nt_smbs          0x0010
+#define SMB_rpc_remote_apis      0x0020
+#define SMB_cap_nt_status        0x0040
+#define SMB_cap_level_II_oplocks 0x0080
+#define SMB_cap_lock_and_read    0x0100
+#define SMB_cap_nt_find          0x0200
+
+/* SMB LANMAN api call defines */
+
+#define SMB_LMapi_SetUserInfo     0x0072
+#define SMB_LMapi_UserPasswordSet 0x0073
+
+/* Structures and defines we use in the client interface */
+
+/* The protocols we might support. Perhaps a bit ambitious, as only RFCNB */
+/* has any support so far 0(sometimes called NBT)                         */
+
+typedef enum {
+    SMB_RFCNB, SMB_IPXNB, SMB_NETBEUI, SMB_X25
+} SMB_Transport_Types;
+
+typedef enum {
+    SMB_Con_FShare, SMB_Con_PShare, SMB_Con_IPC
+} SMB_Con_Types;
+
+typedef enum {
+    SMB_State_NoState, SMB_State_Stopped, SMB_State_Started
+} SMB_State_Types;
+
+/* The following two arrays need to be in step!              */
+/* We must make it possible for callers to specify these ... */
+
+
+extern char *SMB_Prots[];
+
+/*
+ * static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", 
+ * "MICROSOFT NETWORKS 1.03",
+ * "MICROSOFT NETWORKS 3.0",
+ * "DOS LANMAN1.0",
+ * "LANMAN1.0",
+ * "DOS LM1.2X002",
+ * "LM1.2X002",
+ * "DOS LANMAN2.1",
+ * "LANMAN2.1",
+ * "Samba",
+ * "NT LM 0.12",
+ * "NT LANMAN 1.0",
+ * NULL};
+ */
+extern int SMB_Types[];
+
+/*
+ * static int SMB_Types[] = {SMB_P_Core,
+ * SMB_P_CorePlus,
+ * SMB_P_DOSLanMan1,
+ * SMB_P_DOSLanMan1,
+ * SMB_P_LanMan1,
+ * SMB_P_DOSLanMan2,
+ * SMB_P_LanMan2,
+ * SMB_P_LanMan2_1,
+ * SMB_P_LanMan2_1,
+ * SMB_P_NT1,
+ * SMB_P_NT1,
+ * SMB_P_NT1,
+ * -1};
+ */
+typedef struct SMB_Status {
+
+    union {
+       struct {
+           unsigned char ErrorClass;
+           unsigned char Reserved;
+           unsigned short Error;
+       } DosError;
+       unsigned int NtStatus;
+    } status;
+} SMB_Status;
+
+typedef struct SMB_Tree_Structure *SMB_Tree_Handle;
+
+typedef struct SMB_Connect_Def *SMB_Handle_Type;
+
+struct SMB_Connect_Def {
+
+    SMB_Handle_Type Next_Con, Prev_Con;                /* Next and previous conn */
+    int protocol;              /* What is the protocol   */
+    int prot_IDX;              /* And what is the index  */
+    void *Trans_Connect;       /* The connection         */
+
+    /* All these strings should be malloc'd */
+
+    char service[80], username[80], password[80], desthost[80], sock_options[80];
+    char address[80], myname[80];
+
+    SMB_Tree_Handle first_tree, last_tree;     /* List of trees on this server */
+
+    int gid;                   /* Group ID, do we need it?                      */
+    int mid;                   /* Multiplex ID? We might need one per con       */
+    int pid;                   /* Process ID                                    */
+
+    int uid;                   /* Authenticated user id.                        */
+
+    /* It is pretty clear that we need to bust some of */
+    /* these out into a per TCon record, as there may  */
+    /* be multiple TCon's per server, etc ... later    */
+
+    int port;                  /* port to use in case not default, this is a TCPism! */
+
+    int max_xmit;              /* Max xmit permitted by server                  */
+    int Security;              /* 0 = share, 1 = user                           */
+    int Raw_Support;           /* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */
+    BOOL encrypt_passwords;    /* FALSE = don't                          */
+    int MaxMPX, MaxVC, MaxRaw;
+    unsigned int SessionKey, Capabilities;
+    int SvrTZ;                 /* Server Time Zone */
+    int Encrypt_Key_Len;
+    char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40];
+    char Svr_OS[80], Svr_LMType[80], Svr_PDom[80];
+
+};
+
+#ifndef SMBLIB_DEFAULT_DOMAIN
+#define SMBLIB_DEFAULT_DOMAIN "STAFF"
+#endif
+#define SMBLIB_DEFAULT_OSNAME "UNIX of some type"
+#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit"
+#define SMBLIB_MAX_XMIT 65535
+
+#define SMB_Sec_Mode_Share 0
+#define SMB_Sec_Mode_User  1
+
+/* A Tree_Structure                       */
+
+struct SMB_Tree_Structure {
+
+    SMB_Tree_Handle next, prev;
+    SMB_Handle_Type con;
+    char path[129];
+    char device_type[20];
+    int mbs;                   /* Local MBS */
+    int tid;
+
+};
+
+typedef struct SMB_File_Def SMB_File;
+
+struct SMB_File_Def {
+
+    SMB_Tree_Handle tree;
+    char filename[256];                /* We should malloc this ... */
+    UWORD fid;
+    unsigned int lastmod;
+    unsigned int size;         /* Could blow up if 64bit files supported */
+    UWORD access;
+    off_t fileloc;
+
+};
+
+/* global Variables for the library */
+
+extern SMB_State_Types SMBlib_State;
+
+#ifndef SMBLIB_ERRNO
+extern int SMBlib_errno;
+extern int SMBlib_SMB_Error;   /* last Error             */
+#endif
+
+SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type con, SMB_Tree_Handle tree,
+    char *path, char *password, char *dev);
+
+int SMB_Init();
+void SMB_Get_My_Name(char *name, int len);
+int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[]);
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord, char *UserDomain, int precrypted);
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+int SMB_Get_Last_Error();
+
+#endif /* __SMBLIB_PRIV_H__ */
diff --git a/helpers/ntlm_auth/SMB/smbval/smblib-util.c b/helpers/ntlm_auth/SMB/smbval/smblib-util.c
new file mode 100644 (file)
index 0000000..ffb1fcc
--- /dev/null
@@ -0,0 +1,801 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Utility Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "smblib-priv.h"
+#include <malloc.h>
+#include <string.h>
+
+#include "rfcnb.h"
+
+/* global data structures */
+
+static int SMB_Types[] =
+{SMB_P_Core,
+    SMB_P_CorePlus,
+    SMB_P_DOSLanMan1,
+    SMB_P_DOSLanMan1,
+    SMB_P_LanMan1,
+    SMB_P_DOSLanMan2,
+    SMB_P_LanMan2,
+    SMB_P_LanMan2_1,
+    SMB_P_LanMan2_1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    SMB_P_NT1,
+    -1};
+
+static char *SMB_Prots[] =
+{"PC NETWORK PROGRAM 1.0",
+    "MICROSOFT NETWORKS 1.03",
+    "MICROSOFT NETWORKS 3.0",
+    "DOS LANMAN1.0",
+    "LANMAN1.0",
+    "DOS LM1.2X002",
+    "LM1.2X002",
+    "DOS LANMAN2.1",
+    "LANMAN2.1",
+    "Samba",
+    "NT LM 0.12",
+    "NT LANMAN 1.0",
+    NULL};
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void
+SMB_Print_Pkt(FILE fd, RFCNB_Pkt * pkt, BOOL command, int Offset, int Len)
+{
+
+    /* Well, just how do we do this ... print it I suppose */
+
+    /* Print out the SMB header ...                        */
+
+    /* Print the command                                   */
+
+    /* Print the other bits in the header                  */
+
+
+    /* etc                                                 */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *
+SMB_DOSTimToStr(int DOS_time)
+{
+    static char SMB_Time_Temp[48];
+    int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+    SMB_Time_Temp[0] = 0;
+
+    DOS_sec = (DOS_time & 0x001F) * 2;
+    DOS_min = (DOS_time & 0x07E0) >> 5;
+    DOS_hour = ((DOS_time & 0xF800) >> 11);
+
+    DOS_day = (DOS_time & 0x001F0000) >> 16;
+    DOS_month = (DOS_time & 0x01E00000) >> 21;
+    DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+    sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+       DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+    return (SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+ * to a static string which we guarantee is long enough. If verbose is 
+ * true, we print out long form of strings ...                            */
+
+char *
+SMB_AtrToStr(int attribs, BOOL verbose)
+{
+    static char SMB_Attrib_Temp[128];
+
+    SMB_Attrib_Temp[0] = 0;
+
+    if (attribs & SMB_FA_ROF)
+       strcat(SMB_Attrib_Temp, (verbose ? "Read Only " : "R"));
+
+    if (attribs & SMB_FA_HID)
+       strcat(SMB_Attrib_Temp, (verbose ? "Hidden " : "H"));
+
+    if (attribs & SMB_FA_SYS)
+       strcat(SMB_Attrib_Temp, (verbose ? "System " : "S"));
+
+    if (attribs & SMB_FA_VOL)
+       strcat(SMB_Attrib_Temp, (verbose ? "Volume " : "V"));
+
+    if (attribs & SMB_FA_DIR)
+       strcat(SMB_Attrib_Temp, (verbose ? "Directory " : "D"));
+
+    if (attribs & SMB_FA_ARC)
+       strcat(SMB_Attrib_Temp, (verbose ? "Archive " : "A"));
+
+    return (SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int
+SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+{
+    if (tree != NULL) {
+       return (tree->mbs);
+    } else {
+       return (SMBlibE_BAD);
+    }
+}
+
+/* Pick up the Max buffer size */
+
+int
+SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->max_xmit);
+    } else {
+       return (SMBlibE_BAD);
+    }
+
+}
+/* Pickup the protocol index from the connection structure                 */
+
+int
+SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->prot_IDX);
+    } else {
+       return (0xFFFF);        /* Invalid protocol */
+    }
+
+}
+
+/* Pick up the protocol from the connection structure                       */
+
+int
+SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+{
+    if (Con_Handle != NULL) {
+       return (Con_Handle->protocol);
+    } else {
+       return (0xFFFF);        /* Invalid protocol */
+    }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user      */
+/* supplied list, and assume that it is a subset of our list                */
+
+int
+SMB_Figure_Protocol(char *dialects[], int prot_index)
+{
+    int i;
+
+    if (dialects == SMB_Prots) {       /* The jobs is easy, just index into table */
+
+       return (SMB_Types[prot_index]);
+    } else {                   /* Search through SMB_Prots looking for a match */
+
+       for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+           if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) {      /* A match */
+
+               return (SMB_Types[i]);
+
+           }
+       }
+
+       /* If we got here, then we are in trouble, because the protocol was not */
+       /* One we understand ...                                                */
+
+       return (SMB_P_Unknown);
+
+    }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots       */
+/* we return the index of the accepted protocol in NegProt, -1 indicates  */
+/* none acceptible, and our return value is 0 if ok, <0 if problems       */
+
+int
+SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+{
+    struct RFCNB_Pkt *pkt;
+    int prots_len, i, pkt_len, prot, alloc_len;
+    char *p;
+
+    /* Figure out how long the prot list will be and allocate space for it */
+
+    prots_len = 0;
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+       prots_len = prots_len + strlen(Prots[i]) + 2;   /* Account for null etc */
+
+    }
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_negp_len + prots_len;
+
+    /* Make sure that the pkt len is long enough for the max response ...   */
+    /* Which is a problem, because the encryption key len eec may be long   */
+
+    if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+       alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+    } else {
+
+       alloc_len = pkt_len;
+
+    }
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(alloc_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now plug in the bits we need */
+
+    bzero(SMB_Hdr(pkt), SMB_negp_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+    /* Now copy the prot strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+    for (i = 0; Prots[i] != NULL; i++) {
+
+       *p = SMBdialectID;
+       strcpy(p + 1, Prots[i]);
+       p = p + strlen(Prots[i]) + 2;   /* Adjust len of p for null plus dialectID */
+
+    }
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;     /* Failed, check lower layer errno */
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;     /* Failed, check lower layer errno */
+       return (SMBlibE_BAD);
+
+    }
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+    if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+       fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_NegNoProt;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now, unpack the info from the response, if any and evaluate the proto */
+    /* selected. We must make sure it is one we like ...                     */
+
+    Con_Handle->prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+    Con_Handle->protocol = SMB_Figure_Protocol(Prots, prot);
+
+    if (Con_Handle->protocol == SMB_P_Unknown) {       /* No good ... */
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_ProtUnknown;
+       return (SMBlibE_BAD);
+
+    }
+    switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+    case 0x01:                 /* No more info ... */
+
+       break;
+
+    case 13:                   /* Up to and including LanMan 2.1 */
+
+       Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+       Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+       Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+       Con_Handle->max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+       Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+       Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+       Con_Handle->Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+       Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+       Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+       Con_Handle->Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+
+       p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
+       fprintf(stderr, "%8s", (char *) (SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
+       memcpy(Con_Handle->Encrypt_Key, p, 8);
+
+       p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+       strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+       break;
+
+    case 17:                   /* NT LM 0.12 and LN LM 1.0 */
+
+       Con_Handle->Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+       Con_Handle->encrypt_passwords = ((Con_Handle->Security & SMB_sec_encrypt_mask) != 0x00);
+       Con_Handle->Security = Con_Handle->Security & SMB_sec_user_mask;
+
+       Con_Handle->max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+       Con_Handle->MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+       Con_Handle->MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+       Con_Handle->MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+       Con_Handle->SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+       Con_Handle->SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+       Con_Handle->Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+       p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset);
+       memcpy(Con_Handle->Encrypt_Key, p, 8);
+       p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle->Encrypt_Key_Len);
+
+       strncpy(p, Con_Handle->Svr_PDom, sizeof(Con_Handle->Svr_PDom) - 1);
+
+       break;
+
+    default:
+
+#ifdef DEBUG
+       fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+       fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+       break;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Get our hostname */
+
+void
+SMB_Get_My_Name(char *name, int len)
+{
+
+    if (gethostname(name, len) < 0) {  /* Error getting name */
+
+       strncpy(name, "unknown", len);
+
+       /* Should check the error */
+
+#ifdef DEBUG
+       fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+       perror("");
+#endif
+
+    }
+    /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ...               */
+
+SMB_Tree_Handle
+SMB_TreeConnect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle Tree_Handle,
+    char *path,
+    char *password,
+    char *device)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len;
+    char *p;
+    SMB_Tree_Handle tree;
+
+    /* Figure out how much space is needed for path, password, dev ... */
+
+    if ((path == NULL) || (password == NULL) || (device == NULL)) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+       SMBlib_errno = SMBlibE_BadParam;
+       return (NULL);
+
+    }
+    /* The + 2 is because of the \0 and the marker ...                    */
+
+    param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+    /* The -1 accounts for the one byte smb_buf we have because some systems */
+    /* don't like char msg_buf[]                                             */
+
+    pkt_len = SMB_tcon_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (NULL);          /* Should handle the error */
+
+    }
+    /* Now allocate a tree for this to go into ... */
+
+    if (Tree_Handle == NULL) {
+
+       tree = (SMB_Tree_Handle) malloc(sizeof(struct SMB_Tree_Structure));
+
+       if (tree == NULL) {
+
+           RFCNB_Free_Pkt(pkt);
+           SMBlib_errno = SMBlibE_NoSpace;
+           return (NULL);
+
+       }
+    } else {
+
+       tree = Tree_Handle;
+
+    }
+
+    tree->next = tree->prev = NULL;
+    tree->con = Con_Handle;
+    strncpy(tree->path, path, sizeof(tree->path));
+    strncpy(tree->device_type, device, sizeof(tree->device_type));
+
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tcon_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *) (SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+    *p = SMBasciiID;
+    strcpy(p + 1, path);
+    p = p + strlen(path) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, password);
+    p = p + strlen(password) + 2;
+    *p = SMBasciiID;
+    strcpy(p + 1, device);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;
+       return (NULL);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;
+       return (NULL);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       if (Tree_Handle == NULL)
+           free(tree);
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (NULL);
+
+    }
+    tree->tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+    tree->mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+    fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+       tree->tid, tree->mbs);
+#endif
+
+    /* Now link the Tree to the Server Structure ... */
+
+    if (Con_Handle->first_tree == NULL) {
+
+       Con_Handle->first_tree = tree;
+       Con_Handle->last_tree = tree;
+
+    } else {
+
+       Con_Handle->last_tree->next = tree;
+       tree->prev = Con_Handle->last_tree;
+       Con_Handle->last_tree = tree;
+
+    }
+
+    RFCNB_Free_Pkt(pkt);
+    return (tree);
+
+}
+
+int
+SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+{
+    struct RFCNB_Pkt *pkt;
+    int pkt_len;
+
+    pkt_len = SMB_tdis_len;
+
+    pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+       SMBlib_errno = SMBlibE_NoSpace;
+       return (SMBlibE_BAD);   /* Should handle the error */
+
+    }
+    /* Now plug in the values ... */
+
+    bzero(SMB_Hdr(pkt), SMB_tdis_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);      /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle->con->pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle->con->mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle->con->uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle->tid);
+    SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+    /* Now send the packet and sit back ... */
+
+    if (RFCNB_Send(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_SendFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Tree_Handle->con->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = -SMBlibE_RecvFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+    Tree_Handle->tid = 0xFFFF; /* Invalid TID */
+    Tree_Handle->mbs = 0;      /* Invalid     */
+
+#ifdef DEBUG
+
+    fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+    /* What about the tree handle ? */
+
+    if (discard == TRUE) {     /* Unlink it and free it ... */
+
+       if (Tree_Handle->next == NULL)
+           Tree_Handle->con->first_tree = Tree_Handle->prev;
+       else
+           Tree_Handle->next->prev = Tree_Handle->prev;
+
+       if (Tree_Handle->prev == NULL)
+           Tree_Handle->con->last_tree = Tree_Handle->next;
+       else
+           Tree_Handle->prev->next = Tree_Handle->next;
+
+    }
+    RFCNB_Free_Pkt(pkt);
+    return (0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int
+SMB_Get_Last_Error()
+{
+
+    return (SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet          */
+/* We will need macros to extract error class and error code */
+
+int
+SMB_Get_Last_SMB_Err()
+{
+
+    return (SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib  */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] =
+{
+
+    "Request completed sucessfully.",
+    "Server returned a non-zero SMB Error Class and Code.",
+    "A lower layer protocol error occurred.",
+    "Function not yet implemented.",
+    "The protocol negotiated does not support the request.",
+    "No space available for operation.",
+    "One or more bad parameters passed.",
+    "None of the protocols we offered were accepted.",
+    "The attempt to send an SMB request failed. See protocol error info.",
+    "The attempt to get an SMB response failed. See protocol error info.",
+    "The logon request failed, but you were logged in as guest.",
+    "The attempt to call the remote server failed. See protocol error info.",
+    "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+  /* This next one simplifies error handling */
+    "No such error code.",
+    NULL};
+
+int
+SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+{
+
+    if (msg >= 0) {
+
+       strncpy(msgbuf,
+           SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+           len - 1);
+       msgbuf[len - 1] = 0;    /* Make sure it is a string */
+    } else {                   /* Add the lower layer message ... */
+
+       char prot_msg[1024];
+
+       msg = -msg;             /* Make it positive */
+
+       strncpy(msgbuf,
+           SMBlib_Error_Messages[msg > SMBlibE_NoSuchMsg ? SMBlibE_NoSuchMsg : msg],
+           len - 1);
+
+       msgbuf[len - 1] = 0;    /* make sure it is a string */
+
+       if (strlen(msgbuf) < len) {     /* If there is space, put rest in */
+
+           strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+           RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+           strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+       }
+    }
+    return 0;
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/smblib.c b/helpers/ntlm_auth/SMB/smbval/smblib.c
new file mode 100644 (file)
index 0000000..36d5c6d
--- /dev/null
@@ -0,0 +1,574 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Routines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <malloc.h>
+#include <ctype.h>
+#include <string.h>
+
+int SMBlib_errno;
+int SMBlib_SMB_Error;
+#define SMBLIB_ERRNO
+#define uchar unsigned char
+#include "smblib-priv.h"
+
+#include "rfcnb.h"
+#include "smbencrypt.h"
+
+#include <signal.h>
+
+#define DEBUG
+
+SMB_State_Types SMBlib_State;
+
+/* Initialize the SMBlib package     */
+
+int
+SMB_Init()
+{
+
+    SMBlib_State = SMB_State_Started;
+
+    signal(SIGPIPE, SIG_IGN);  /* Ignore these ... */
+
+/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Init();
+
+#endif
+
+    return 0;
+
+}
+
+int
+SMB_Term()
+{
+
+#ifdef SMBLIB_INSTRUMENT
+
+    SMBlib_Instrument_Term();  /* Clean up and print results */
+
+#endif
+
+    return 0;
+
+}
+
+/* SMB_Create: Create a connection structure and return for later use */
+/* We have other helper routines to set variables                     */
+
+SMB_Handle_Type
+SMB_Create_Con_Handle()
+{
+
+    SMBlib_errno = SMBlibE_NotImpl;
+    return (NULL);
+
+}
+
+int
+SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
+{
+
+
+    if (RFCNB_Set_Sock_NoDelay(Con_Handle->Trans_Connect, yn) < 0) {
+
+#ifdef DEBUG
+#endif
+
+       fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
+
+    }
+    return (0);
+
+}
+
+/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
+/* or anything else ...                                                  */
+
+SMB_Handle_Type
+SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+    char *server, char *NTdomain)
+{
+    SMB_Handle_Type con;
+    char called[80], calling[80], *address;
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+       if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return NULL;
+       }
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, "");
+    strcpy(con->username, "");
+    strcpy(con->password, "");
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->desthost, server);
+    strcpy(con->PDomain, NTdomain);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    /* ugh. This is horribly broken. */
+/*   SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); */
+    /* hacked by Kinkie */
+    i = gethostname(con->myname, sizeof(con->myname));
+    if (i == -1) {
+       strcpy(con->myname, "unknown");
+    } else {
+       if (NULL != (address = strchr(con->myname, '.'))) {
+           *address = '\0';    /* truncate at first '.' */
+       }
+    }
+
+
+    con->port = 0;             /* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;       /* This will do for now ... */
+    con->uid = 0;              /* Until we have done a logon, no uid ... */
+    con->gid = getgid();
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(server); i++)
+       called[i] = toupper(server[i]);
+
+    called[strlen(server)] = 0;        /* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+       calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;  /* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+       address = con->desthost;
+    else
+       address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+       calling,
+       address,                /* Protocol specific */
+       con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+       if (Con_Handle == NULL) {
+           Con_Handle = NULL;
+           free(con);
+       }
+       SMBlib_errno = -SMBlibE_CallFailed;
+       return NULL;
+
+    }
+    return (con);
+
+}
+
+/* SMB_Connect: Connect to the indicated server                       */
+/* If Con_Handle == NULL then create a handle and connect, otherwise  */
+/* use the handle passed                                              */
+
+char *SMB_Prots_Restrict[] =
+{"PC NETWORK PROGRAM 1.0",
+    NULL};
+
+
+SMB_Handle_Type
+SMB_Connect(SMB_Handle_Type Con_Handle,
+    SMB_Tree_Handle * tree,
+    char *service,
+    char *username,
+    char *password)
+{
+    SMB_Handle_Type con;
+    char *host, *address;
+    char temp[80], called[80], calling[80];
+    int i;
+
+    /* Get a connection structure if one does not exist */
+
+    con = Con_Handle;
+
+    if (Con_Handle == NULL) {
+
+       if ((con = (struct SMB_Connect_Def *) malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           return NULL;
+       }
+    }
+    /* Init some things ... */
+
+    strcpy(con->service, service);
+    strcpy(con->username, username);
+    strcpy(con->password, password);
+    strcpy(con->sock_options, "");
+    strcpy(con->address, "");
+    strcpy(con->PDomain, SMBLIB_DEFAULT_DOMAIN);
+    strcpy(con->OSName, SMBLIB_DEFAULT_OSNAME);
+    strcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE);
+    con->first_tree = con->last_tree = NULL;
+
+    SMB_Get_My_Name(con->myname, sizeof(con->myname));
+
+    con->port = 0;             /* No port selected */
+
+    /* Get some things we need for the SMB Header */
+
+    con->pid = getpid();
+    con->mid = con->pid;       /* This will do for now ... */
+    con->uid = 0;              /* Until we have done a logon, no uid */
+    con->gid = getgid();
+
+    /* Now figure out the host portion of the service */
+
+    strcpy(temp, service);
+    host = (char *) strtok(temp, "/\\");       /* Separate host name portion */
+    strcpy(con->desthost, host);
+
+    /* Now connect to the remote end, but first upper case the name of the
+     * service we are going to call, sine some servers want it in uppercase */
+
+    for (i = 0; i < strlen(host); i++)
+       called[i] = toupper(host[i]);
+
+    called[strlen(host)] = 0;  /* Make it a string */
+
+    for (i = 0; i < strlen(con->myname); i++)
+       calling[i] = toupper(con->myname[i]);
+
+    calling[strlen(con->myname)] = 0;  /* Make it a string */
+
+    if (strcmp(con->address, "") == 0)
+       address = con->desthost;
+    else
+       address = con->address;
+
+    con->Trans_Connect = RFCNB_Call(called,
+       calling,
+       address,                /* Protocol specific */
+       con->port);
+
+    /* Did we get one? */
+
+    if (con->Trans_Connect == NULL) {
+
+       if (Con_Handle == NULL) {
+           free(con);
+           Con_Handle = NULL;
+       }
+       SMBlib_errno = -SMBlibE_CallFailed;
+       return NULL;
+
+    }
+    /* Now, negotiate the protocol */
+
+    if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
+
+       /* Hmmm what should we do here ... We have a connection, but could not
+        * negotiate ...                                                      */
+
+       return NULL;
+
+    }
+    /* Now connect to the service ... */
+
+    if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
+
+       return NULL;
+
+    }
+    return (con);
+
+}
+
+/* Logon to the server. That is, do a session setup if we can. We do not do */
+/* Unicode yet!                                                             */
+
+int
+SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+    char *PassWord, char *UserDomain, int precrypted)
+{
+    struct RFCNB_Pkt *pkt;
+    int param_len, pkt_len, pass_len;
+    char *p, pword[128];
+
+    /* First we need a packet etc ... but we need to know what protocol has  */
+    /* been negotiated to figure out if we can do it and what SMB format to  */
+    /* use ...                                                               */
+
+    if (Con_Handle->protocol < SMB_P_LanMan1) {
+
+       SMBlib_errno = SMBlibE_ProtLow;
+       return (SMBlibE_BAD);
+
+    }
+    if (precrypted) {
+       pass_len = 24;
+       memcpy(pword, PassWord, 24);
+    } else {
+       strcpy(pword, PassWord);
+       if (Con_Handle->encrypt_passwords) {
+           pass_len = 24;
+           SMBencrypt((uchar *) PassWord, (uchar *) Con_Handle->Encrypt_Key, (uchar *) pword);
+       } else
+           pass_len = strlen(pword);
+    }
+
+    /* Now build the correct structure */
+
+    if (Con_Handle->protocol < SMB_P_NT1) {
+
+       param_len = strlen(UserName) + 1 + pass_len + 1 +
+           strlen(UserDomain) + 1 +
+           strlen(Con_Handle->OSName) + 1;
+
+       pkt_len = SMB_ssetpLM_len + param_len;
+
+       pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+       if (pkt == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
+           return (SMBlibE_BAD);       /* Should handle the error */
+       }
+       bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
+       SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);   /* Plunk in IDF */
+       *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+       *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
+       *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle->pid);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
+
+       /* Now copy the param strings in with the right stuff */
+
+       p = (char *) (SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
+
+       /* Copy  in password, then the rest. Password has a null at end */
+
+       memcpy(p, pword, pass_len);
+
+       p = p + pass_len + 1;
+
+       strcpy(p, UserName);
+       p = p + strlen(UserName);
+       *p = 0;
+
+       p = p + 1;
+
+       strcpy(p, UserDomain);
+       p = p + strlen(UserDomain);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->OSName);
+       p = p + strlen(Con_Handle->OSName);
+       *p = 0;
+
+    } else {
+
+       /* We don't admit to UNICODE support ... */
+
+       param_len = strlen(UserName) + 1 + pass_len +
+           strlen(UserDomain) + 1 +
+           strlen(Con_Handle->OSName) + 1 +
+           strlen(Con_Handle->LMType) + 1;
+
+       pkt_len = SMB_ssetpNTLM_len + param_len;
+
+       pkt = (struct RFCNB_Pkt *) RFCNB_Alloc_Pkt(pkt_len);
+
+       if (pkt == NULL) {
+
+           SMBlib_errno = SMBlibE_NoSpace;
+           fprintf(stderr, "SMB_Logon_server: Couldn't allocate packet\n");
+           return (-1);        /* Should handle the error */
+       }
+       bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
+       SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);   /* Plunk in IDF */
+       *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle->pid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle->mid);
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle->uid);
+       *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
+       *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+       SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
+       SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
+       SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
+
+       /* Now copy the param strings in with the right stuff */
+
+       p = (char *) (SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
+
+       /* Copy  in password, then the rest. Password has no null at end */
+
+       memcpy(p, pword, pass_len);
+
+       p = p + pass_len;
+
+       strcpy(p, UserName);
+       p = p + strlen(UserName);
+       *p = 0;
+
+       p = p + 1;
+
+       strcpy(p, UserDomain);
+       p = p + strlen(UserDomain);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->OSName);
+       p = p + strlen(Con_Handle->OSName);
+       *p = 0;
+       p = p + 1;
+
+       strcpy(p, Con_Handle->LMType);
+       p = p + strlen(Con_Handle->LMType);
+       *p = 0;
+
+    }
+
+    /* Now send it and get a response */
+
+    if (RFCNB_Send(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error sending SessSetupX request\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_SendFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Now get the response ... */
+
+    if (RFCNB_Recv(Con_Handle->Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+       fprintf(stderr, "Error receiving response to SessSetupAndX\n");
+#endif
+
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_RecvFailed;
+       return (SMBlibE_BAD);
+
+    }
+    /* Check out the response type ... */
+
+    if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {     /* Process error */
+
+#ifdef DEBUG
+       fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
+           CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+           SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+       SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+       RFCNB_Free_Pkt(pkt);
+       SMBlib_errno = SMBlibE_Remote;
+       return (SMBlibE_BAD);
+
+    }
+/** @@@ mdz: check for guest login { **/
+    if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1) {
+       /* do we allow guest login? NO! */
+       return (SMBlibE_BAD);
+
+    }
+/** @@@ mdz: } **/
+
+
+#ifdef DEBUG
+    fprintf(stderr, "SessSetupAndX response. Action = %i\n",
+       SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
+#endif
+
+    /* Now pick up the UID for future reference ... */
+
+    Con_Handle->uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
+    RFCNB_Free_Pkt(pkt);
+
+    return (0);
+
+}
+
+
+/* Disconnect from the server, and disconnect all tree connects */
+
+int
+SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
+{
+
+    /* We just disconnect the connection for now ... */
+    if (Con_Handle != NULL)
+       RFCNB_Hangup(Con_Handle->Trans_Connect);
+
+    if (!KeepHandle)
+       free(Con_Handle);
+
+    return (0);
+
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/smblib.h b/helpers/ntlm_auth/SMB/smbval/smblib.h
new file mode 100644 (file)
index 0000000..92467a6
--- /dev/null
@@ -0,0 +1,98 @@
+/* UNIX SMBlib NetBIOS implementation
+ * 
+ * Version 1.0
+ * SMBlib Defines
+ * 
+ * Copyright (C) Richard Sharpe 1996
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "std-defines.h"
+#include "smblib-common.h"
+
+/* Just define all the entry points */
+
+/* Create a handle to allow us to set/override some parameters ...       */
+
+void *SMB_Create_Con_Handle();
+
+/* Connect to a server, but do not do a tree con etc ... */
+
+void *SMB_Connect_Server(void *Con, char *server, char *NTdomain);
+
+/* Connect to a server and give us back a handle. If Con == NULL, create */
+/* The handle and populate it with defaults                              */
+
+void *SMB_Connect(void *Con, void **tree,
+    char *name, char *User, char *Password);
+
+/* Negotiate a protocol                                                  */
+
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+
+/* Connect to a tree ...                                                 */
+
+void *SMB_TreeConnect(void *con_handle, void *tree_handle,
+    char *path, char *password, char *dev);
+
+/* Disconnect a tree ...                                                 */
+
+int SMB_TreeDisconect(void *tree_handle);
+
+/* Open a file                                                           */
+
+void *SMB_Open(void *tree_handle,
+    void *file_handle,
+    char *file_name,
+    unsigned short mode,
+    unsigned short search);
+
+/* Close a file                                                          */
+
+int SMB_Close(void *file_handle);
+
+/* Disconnect from server. Has flag to specify whether or not we keep the */
+/* handle.                                                                */
+
+int SMB_Discon(void *Con, BOOL KeepHandle);
+
+void *SMB_Create(void *Tree_Handle,
+    void *File_Handle,
+    char *file_name,
+    short search);
+
+int SMB_Delete(void *tree, char *file_name, short search);
+
+int SMB_Create_Dir(void *tree, char *dir_name);
+
+int SMB_Delete_Dir(void *tree, char *dir_name);
+
+int SMB_Check_Dir(void *tree, char *dir_name);
+
+int SMB_Get_Last_Error();
+
+int SMB_Get_Last_SMB_Err();
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+void *SMB_Logon_And_TCon(void *con, void *tree, char *user, char *pass,
+    char *service, char *st);
+
+
+#define SMBLIB_DEFAULT_DOMAIN "anydom"
diff --git a/helpers/ntlm_auth/SMB/smbval/std-defines.h b/helpers/ntlm_auth/SMB/smbval/std-defines.h
new file mode 100644 (file)
index 0000000..a9968c5
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __STD_DEFINES__
+#define __STD_DEFINES__
+
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * SMBlib Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ * 
+ * One day we will conditionalize these on OS types ... */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#endif /* __STD_DEFINES__ */
diff --git a/helpers/ntlm_auth/SMB/smbval/std-includes.h b/helpers/ntlm_auth/SMB/smbval/std-includes.h
new file mode 100644 (file)
index 0000000..2426899
--- /dev/null
@@ -0,0 +1,45 @@
+/* RFCNB Standard includes ... */
+/*
+ * 
+ * RFCNB Standard Includes
+ * 
+ * Copyright (C) 1996, Richard Sharpe
+ * 
+ * One day we will conditionalize these on OS types ... */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Pick up define for INADDR_NONE */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
diff --git a/helpers/ntlm_auth/SMB/smbval/valid.c b/helpers/ntlm_auth/SMB/smbval/valid.c
new file mode 100644 (file)
index 0000000..cdefa99
--- /dev/null
@@ -0,0 +1,105 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include "smblib-priv.h"
+#include "valid.h"
+
+SMB_Handle_Type SMB_Connect_Server(void *, char *, char *);
+
+int
+Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN)
+{
+    int pass_is_precrypted_p = 0;
+    char *SMB_Prots[] =
+    {
+/*              "PC NETWORK PROGRAM 1.0", */
+/*              "MICROSOFT NETWORKS 1.03", */
+/*              "MICROSOFT NETWORKS 3.0", */
+       "LANMAN1.0",
+       "LM1.2X002",
+       "Samba",
+/*              "NT LM 0.12", */
+/*              "NT LANMAN 1.0", */
+       NULL};
+    SMB_Handle_Type con;
+
+    SMB_Init();
+    con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+    if (con == NULL) {         /* Error ... */
+       con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+       if (con == NULL) {
+           return (NTV_SERVER_ERROR);
+       }
+    }
+    if (SMB_Negotiate(con, SMB_Prots) < 0) {   /* An error */
+       SMB_Discon(con, 0);
+       return (NTV_PROTOCOL_ERROR);
+    }
+    /* Test for a server in share level mode do not authenticate against it */
+    if (con->Security == 0) {
+       SMB_Discon(con, 0);
+       return (NTV_PROTOCOL_ERROR);
+    }
+    if (SMB_Logon_Server(con, USERNAME, PASSWORD, DOMAIN, pass_is_precrypted_p) < 0) {
+       SMB_Discon(con, 0);
+       return (NTV_LOGON_ERROR);
+    }
+    SMB_Discon(con, 0);
+    return (NTV_NO_ERROR);
+}
+
+void *
+NTLM_Connect(char *SERVER, char *BACKUP, char *DOMAIN, char *nonce)
+{
+    char *SMB_Prots[] =
+    {
+/*              "PC NETWORK PROGRAM 1.0", */
+/*              "MICROSOFT NETWORKS 1.03", */
+/*              "MICROSOFT NETWORKS 3.0", */
+       "LANMAN1.0",
+       "LM1.2X002",
+       "Samba",
+/*              "NT LM 0.12", */
+/*              "NT LANMAN 1.0", */
+       NULL};
+    SMB_Handle_Type con;
+
+    SMB_Init();
+    con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+    if (con == NULL) {         /* Error ... */
+       con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+       if (con == NULL) {
+           return (NULL);
+       }
+    }
+    if (SMB_Negotiate(con, SMB_Prots) < 0) {   /* An error */
+       SMB_Discon(con, 0);
+       return (NULL);
+    }
+    /* Test for a server in share level mode do not authenticate against it */
+    if (con->Security == 0) {
+       SMB_Discon(con, 0);
+       return (NULL);
+    }
+    memcpy(nonce, con->Encrypt_Key, 8);
+
+    return (con);
+}
+
+int
+NTLM_Auth(void *handle, char *USERNAME, char *PASSWORD, int flag)
+{
+    SMB_Handle_Type con = handle;
+
+    if (SMB_Logon_Server(con, USERNAME, PASSWORD, NULL, flag) < 0) {
+       return (NTV_LOGON_ERROR);
+    }
+    return (NTV_NO_ERROR);
+}
+
+void
+NTLM_Disconnect(void *handle)
+{
+    SMB_Handle_Type con = handle;
+    SMB_Discon(con, 0);
+}
diff --git a/helpers/ntlm_auth/SMB/smbval/valid.h b/helpers/ntlm_auth/SMB/smbval/valid.h
new file mode 100644 (file)
index 0000000..4c2f6d2
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _VALID_H_
+#define _VALID_H_
+/* SMB User verification function */
+
+#define NTV_NO_ERROR 0
+#define NTV_SERVER_ERROR 1
+#define NTV_PROTOCOL_ERROR 2
+#define NTV_LOGON_ERROR 3
+
+int Valid_User(char *USERNAME, char *PASSWORD, char *SERVER, char *BACKUP, char *DOMAIN);
+void *NTLM_Connect(char *SERVER, char *BACKUP, char *DOMAIN, char *nonce);
+int NTLM_Auth(void *handle, char *USERNAME, char *PASSWORD, int flag);
+void NTLM_Disconnect(void *handle);
+
+#endif
diff --git a/helpers/ntlm_auth/fakeauth/Makefile.in b/helpers/ntlm_auth/fakeauth/Makefile.in
new file mode 100644 (file)
index 0000000..e318416
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:50 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+FAKEAUTH_AUTH_EXE      = fakeauth_auth$(exec_suffix)
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+CRYPTLIB       = @CRYPTLIB@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS          = $(FAKEAUTH_AUTH_EXE)
+OBJS           = fakeauth_auth.o
+
+all:    $(FAKEAUTH_AUTH_EXE)
+
+$(OBJS): $(top_srcdir)/include/version.h
+
+$(FAKEAUTH_AUTH_EXE): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/ntlm_auth/fakeauth/fakeauth_auth.c b/helpers/ntlm_auth/fakeauth/fakeauth_auth.c
new file mode 100644 (file)
index 0000000..e7603a2
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ *
+ * AUTHOR: Robert Collins <rbtcollins@hotmail.com>
+ *
+ * Example ntlm authentication program for Squid, based on the
+ * original proxy_auth code from client_side.c, written by
+ * Jon Thackray <jrmt@uk.gdscorp.com>. and the inital ntlm code
+ * Andy Doran.
+ *
+ * This code gets the username and returns it. No validation is done.
+ * and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP
+ * if you can.
+ */
+
+#include "config.h"
+
+#include "ntlm.h"
+#include "util.h"
+#include <ctype.h>
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+
+#define ERR    "ERR\n"
+#define OK     "OK\n"
+
+#if 0
+#define NTLM_STATIC_CHALLENGE "deadbeef"
+#endif
+static char *authenticate_ntlm_domain = "LIFELESSWKS";
+
+/* NTLM authentication by ad@netbsd.org - 07/1999 */
+/* XXX this is not done cleanly... */
+
+/* makes a null-terminated string lower-case. Changes CONTENTS! */
+static void
+lc(char *string)
+{
+    char *p = string, c;
+    while ((c = *p)) {
+       *p = tolower(c);
+       p++;
+    }
+}
+
+
+/*
+ * Generates a challenge request. The randomness of the 8 byte 
+ * challenge strings can be guarenteed to be poor at best.
+ */
+void
+ntlmMakeChallenge(struct ntlm_challenge *chal)
+{
+#ifndef NTLM_STATIC_CHALLENGE
+    static unsigned hash;
+    int r;
+#endif
+    char *d;
+    int i;
+
+    memset(chal, 0, sizeof(*chal));
+    memcpy(chal->hdr.signature, "NTLMSSP", 8);
+    chal->flags = WSWAP(0x00018206);
+    chal->hdr.type = WSWAP(NTLM_CHALLENGE);
+    chal->unknown[6] = SSWAP(0x003a);
+
+    d = (char *) chal + 48;
+    i = 0;
+
+    if (authenticate_ntlm_domain != NULL)
+       while (authenticate_ntlm_domain[i++]);
+
+
+    chal->target.offset = WSWAP(48);
+    chal->target.maxlen = SSWAP(i);
+    chal->target.len = chal->target.maxlen;
+
+#ifdef NTLM_STATIC_CHALLENGE
+    memcpy(chal->challenge, NTLM_STATIC_CHALLENGE, 8);
+#else
+    r = (int) rand();
+    r = (hash ^ r) + r;
+
+    for (i = 0; i < 8; i++) {
+       chal->challenge[i] = r;
+       r = (r >> 2) ^ r;
+    }
+
+    hash = r;
+#endif
+}
+
+/*
+ * Check the vailidity of a request header. Return -1 on error.
+ */
+int
+ntlmCheckHeader(struct ntlmhdr *hdr, int type)
+{
+    /* 
+     * Must be the correct security package and request type. The
+     * 8 bytes compared includes the ASCII 'NUL'. 
+     */
+    if (memcmp(hdr->signature, "NTLMSSP", 8) != 0) {
+       fprintf(stderr, "ntlmCheckHeader: bad header signature\n");
+       return (-1);
+    }
+    if (type == NTLM_ANY)
+       return 0;
+
+    if (WSWAP(hdr->type) != type) {
+/* don't report this error - it's ok as we do a if() around this function */
+//      fprintf(stderr, "ntlmCheckHeader: type is %d, wanted %d\n",
+       //          WSWAP(hdr->type), type);
+       return (-1);
+    }
+    return (0);
+}
+
+/*
+ * Extract a string from an NTLM request and return as ASCII.
+ */
+char *
+ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags)
+{
+    static char buf[512];
+    u_short *s, c;
+    char *d, *sc;
+    int l, o;
+
+    l = SSWAP(str->len);
+    o = WSWAP(str->offset);
+
+    /* Sanity checks. XXX values arbitrarialy chosen */
+    if (l <= 0 || l >= 32 || o >= 256) {
+       fprintf(stderr, "ntlmGetString: insane: l:%d o:%d\n", l, o);
+       return (NULL);
+    }
+    if ((flags & 2) == 0) {
+       /* UNICODE string */
+       s = (u_short *) ((char *) hdr + o);
+       d = buf;
+
+       for (l >>= 1; l; s++, l--) {
+           c = SSWAP(*s);
+           if (c > 254 || c == '\0' || !isprint(c)) {
+               fprintf(stderr, "ntlmGetString: bad uni: %04x\n", c);
+               return (NULL);
+           }
+           *d++ = c;
+           fprintf(stderr, "ntlmGetString: conv: '%c'\n", c);
+       }
+
+       *d = 0;
+    } else {
+       /* ASCII string */
+       sc = (char *) hdr + o;
+       d = buf;
+
+       for (; l; l--) {
+           if (*sc == '\0' || !isprint(*sc)) {
+               fprintf(stderr, "ntlmGetString: bad ascii: %04x\n", *sc);
+               return (NULL);
+           }
+           *d++ = *sc++;
+       }
+
+       *d = 0;
+    }
+
+    return (buf);
+}
+
+/*
+ * Decode the strings in an NTLM authentication request
+ */
+int
+ntlmDecodeAuth(struct ntlm_authenticate *auth, char *buf, size_t size)
+{
+    char *p, *origbuf;
+    int s;
+
+    if (!buf) {
+       return 1;
+    }
+    origbuf = buf;
+    if (ntlmCheckHeader(&auth->hdr, NTLM_AUTHENTICATE)) {
+
+       fprintf(stderr, "ntlmDecodeAuth: header check fails\n");
+       return -1;
+    }
+/* only on when you need to debug
+ * fprintf(stderr,"ntlmDecodeAuth: size of %d\n", size);
+ * fprintf(stderr,"ntlmDecodeAuth: flg %08x\n", auth->flags);
+ * fprintf(stderr,"ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len);
+ */
+    if ((p = ntlmGetString(&auth->hdr, &auth->domain, 2)) == NULL)
+       p = authenticate_ntlm_domain;
+//      fprintf(stderr,"ntlmDecodeAuth: Domain '%s'.\n",p);
+    if ((s = strlen(p) + 1) >= size)
+       return 1;
+    strcpy(buf, p);
+//      fprintf(stdout,"ntlmDecodeAuth: Domain '%s'.\n",buf);
+
+    size -= s;
+    buf += (s - 1);
+    *buf++ = '\\';             /* Using \ is more consistent with MS-proxy */
+
+    p = ntlmGetString(&auth->hdr, &auth->user, 2);
+    if ((s = strlen(p) + 1) >= size)
+       return 1;
+    while (*p)
+       *buf++ = (*p++);        //tolower
+
+    *buf++ = '\0';
+    size -= s;
+//      fprintf(stderr, "ntlmDecodeAuth: user: %s%s\n",origbuf, p);
+
+
+    return 0;
+}
+
+
+int
+main()
+{
+    char buf[256];
+    char user[256], *p, *cleartext;
+    struct ntlm_challenge chal;
+    int len;
+    char *data = NULL;
+
+    setbuf(stdout, NULL);
+    while (fgets(buf, 256, stdin) != NULL) {
+       user[0] = '\0';         /*no usercode */
+
+       if ((p = strchr(buf, '\n')) != NULL)
+           *p = '\0';          /* strip \n */
+#if defined(NTLMHELPPROTOCOLV3) || !defined(NTLMHELPPROTOCOLV2)
+       if (strncasecmp(buf, "YR", 2) == 0) {
+           ntlmMakeChallenge(&chal);
+           len =
+               sizeof(chal) - sizeof(chal.pad) +
+               SSWAP(chal.target.maxlen);
+           data = (char *) base64_encode_bin((char *) &chal, len);
+           printf("TT %s\n", data);
+       } else if (strncasecmp(buf, "KK ", 3) == 0) {
+           cleartext = (char *) uudecode(buf + 3);
+           if (!ntlmCheckHeader((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) {
+               if (!ntlmDecodeAuth((struct ntlm_authenticate *) cleartext, user, 256)) {
+                   lc(user);
+                   printf("AF %s\n", user);
+               } else {
+                   lc(user);
+                   printf("NA invalid credentials%s\n", user);
+               }
+           } else {
+               lc(user);
+               printf("BH wrong packet type!%s\n", user);
+           }
+       }
+#endif
+#ifdef NTLMHELPPROTOCOLV2
+/* V2 of the protocol */
+       if (strncasecmp(buf, "RESET", 5) == 0) {
+           printf("RESET OK\n");
+       } else {
+           cleartext = (char *) uudecode(buf);
+           if (!ntlmCheckHeader((struct ntlmhdr *) cleartext, NTLM_NEGOTIATE)) {
+               ntlmMakeChallenge(&chal);
+               len =
+                   sizeof(chal) - sizeof(chal.pad) +
+                   SSWAP(chal.target.maxlen);
+               data = (char *) base64_encode_bin((char *) &chal, len);
+               printf("CH %s\n", data);
+           } else if (!ntlmCheckHeader
+               ((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) {
+               if (!ntlmDecodeAuth
+                   ((struct ntlm_authenticate *) cleartext, user, 256)) {
+                   lc(user);
+                   printf("OK %s\n", user);
+               } else {
+                   lc(user);
+                   printf("ERR %s\n", user);
+               }
+           } else {
+               lc(user);
+               printf("ERR %s\n", user);
+           }
+       }
+#endif /*v2 */
+    }
+    exit(0);
+}
diff --git a/helpers/ntlm_auth/fakeauth/ntlm.h b/helpers/ntlm_auth/fakeauth/ntlm.h
new file mode 100644 (file)
index 0000000..f14250f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * $Id: ntlm.h,v 1.1 2001/01/07 23:36:50 hno Exp $
+ *
+ * AUTHOR: Andy Doran <ad@netbsd.org>
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *  
+ */
+
+#ifndef _NTLM_H_
+#define _NTLM_H_
+
+/* undefine this to have strict protocol adherence. You don't really need
+ * that though */
+#define IGNORANCE_IS_BLISS
+
+#include <sys/types.h>
+
+/* All of this cruft is little endian */
+#ifdef WORDS_BIGENDIAN
+#define SSWAP(x)       (bswap16((x)))
+#define WSWAP(x)       (bswap32((x)))
+#else
+#define SSWAP(x)       (x)
+#define WSWAP(x)       (x)
+#endif
+
+/* NTLM request types that we know about */
+#define NTLM_NEGOTIATE         1
+#define NTLM_CHALLENGE         2
+#define NTLM_AUTHENTICATE      3
+#define NTLM_ANY          0
+
+/* Header proceeding each request */
+typedef struct ntlmhdr {
+    char signature[8];         /* NTLMSSP */
+    int32_t type;              /* One of NTLM_* from above */
+} ntlmhdr;
+
+/* String header. String data resides at the end of the request */
+typedef struct strhdr {
+    int16_t len;               /* Length in bytes */
+    int16_t maxlen;            /* Allocated space in bytes */
+    int32_t offset;            /* Offset from start of request */
+} strhdr;
+
+/* Negotiation request sent by client */
+struct ntlm_negotiate {
+    ntlmhdr hdr;               /* NTLM header */
+    int32_t flags;             /* Request flags */
+    strhdr domain;             /* Domain we wish to authenticate in */
+    strhdr workstation;                /* Client workstation name */
+    char pad[256];             /* String data */
+};
+
+/* Challenge request sent by server. */
+struct ntlm_challenge {
+    ntlmhdr hdr;               /* NTLM header */
+    strhdr target;             /* Authentication target (domain/server ...) */
+    int32_t flags;             /* Request flags */
+    u_char challenge[8];       /* Challenge string */
+    int16_t unknown[8];                /* Some sort of context data */
+    char pad[256];             /* String data */
+};
+
+/* Authentication request sent by client in response to challenge */
+struct ntlm_authenticate {
+    ntlmhdr hdr;               /* NTLM header */
+    strhdr lmresponse;         /* LANMAN challenge response */
+    strhdr ntresponse;         /* NT challenge response */
+    strhdr domain;             /* Domain to authenticate against */
+    strhdr user;               /* Username */
+    strhdr workstation;                /* Workstation name */
+    strhdr sessionkey;         /* Session key for server's use */
+    int32_t flags;             /* Request flags */
+    char pad[256 * 6];         /* String data */
+};
+
+char *ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags);
+void ntlmMakeChallenge(struct ntlm_challenge *chal);
+int ntlmCheckHeader(struct ntlmhdr *hdr, int type);
+int ntlmCheckNegotiation(struct ntlm_negotiate *neg);
+int ntlmAuthenticate(struct ntlm_authenticate *neg);
+
+#endif /* _NTLM_H_ */
diff --git a/helpers/ntlm_auth/no_check/Makefile.in b/helpers/ntlm_auth/no_check/Makefile.in
new file mode 100644 (file)
index 0000000..30c2182
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:50 hno Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix         = @prefix@
+exec_prefix    = @exec_prefix@
+exec_suffix    = @exec_suffix@
+top_srcdir     = @top_srcdir@
+bindir         = @bindir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+
+# Gotta love the DOS legacy
+#
+NO_CHECK       = no_check
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+INSTALL                = @INSTALL@
+INSTALL_BIN    = @INSTALL_PROGRAM@
+CRYPTLIB       = @CRYPTLIB@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
+XTRA_LIBS      = @XTRA_LIBS@
+XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
+SHELL          = /bin/sh
+
+
+INCLUDE                = -I. -I../../../../../include -I$(top_srcdir)/include
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS      = -L../../../../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS          = $(NO_CHECK).pl
+OBJS           = $(NO_CHECK)
+
+all:    $(PROGS)
+
+#$(OBJS): 
+
+$(NO_CHECK).pl: $(OBJS)
+       cp $(srcdir)/$(NO_CHECK) ./$(NO_CHECK).pl
+
+install-mkdirs:
+       -@if test ! -d $(prefix); then \
+               echo "mkdir $(prefix)"; \
+               mkdir $(prefix); \
+       fi
+       -@if test ! -d $(bindir); then \
+               echo "mkdir $(bindir)"; \
+               mkdir $(bindir); \
+       fi
+
+install: all install-mkdirs
+       @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
+               echo $(INSTALL_BIN) $$f $(bindir); \
+               $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) -f $(bindir)/-$$f; \
+               fi; \
+       done
+
+clean: 
+       -rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+       -rm -f Makefile
+
+depend:
+       $(MAKEDEPEND) -I../include -I. -fMakefile *.c
diff --git a/helpers/ntlm_auth/no_check/README.no_check_ntlm_auth b/helpers/ntlm_auth/no_check/README.no_check_ntlm_auth
new file mode 100644 (file)
index 0000000..19d895a
--- /dev/null
@@ -0,0 +1,10 @@
+This is a dummy NTLM authentication module for Squid.
+It performs the NTLM challenge, but then it doesn't verify the
+user's credentials, it just takes the client's domain and username
+at face value.
+It's included mostly for demonstration purposes.
+
+(C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+Distributed freely under the terms of the GNU General Public License, 
+version 2. For the licensing terms, see the file COPYING that
+came with Squid.
diff --git a/include/ntlmauth.h b/include/ntlmauth.h
new file mode 100644 (file)
index 0000000..babec47
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * $Id: ntlmauth.h,v 1.1 2001/01/07 23:36:35 hno Exp $
+ *
+ * * * * * * * * Legal stuff * * * * * * *
+ *
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *   inspired by previous work by Andy Doran.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * * * * * * * * Declaration of intents * * * * * * *
+ *
+ * This header contains definitions and defines allowing to decode and
+ * understand NTLM packets, as sent by Internet Explorer.
+ * It's put here as it is a common utility to all HTLM-enabled modules.
+ */
+
+#ifndef _NTLMAUTH_H_
+#define _NTLMAUTH_H_
+
+#include <sys/types.h>         /* for *int32_t */
+
+/* All of this cruft is little endian */
+#ifdef WORDS_BIGENDIAN
+#define SSWAP(x)       (bswap16((x)))
+#define WSWAP(x)       (bswap32((x)))
+#else
+#define SSWAP(x)       (x)
+#define WSWAP(x)       (x)
+#endif
+
+/* Used internally. Microsoft seems to think this is right, I believe them.
+ * Right. */
+#define MAX_FIELD_LENGTH 300   /* max length of an NTLMSSP field */
+
+
+/* Here start the NTLMSSP definitions */
+/* NTLM request types that we know about */
+#define NTLM_NEGOTIATE         1
+#define NTLM_CHALLENGE         2
+#define NTLM_CHALLENGE_HEADER_OFFSET 40
+#define NTLM_AUTHENTICATE      3
+
+#define NONCE_LEN 8
+
+/* negotiate request flags */
+#define NEGOTIATE_UNICODE              0x0001
+#define NEGOTIATE_ASCII                0x0002
+#define NEGOTIATE_REQUEST_TARGET       0x0004
+#define NEGOTIATE_REQUEST_SIGN         0x0010
+#define NEGOTIATE_REQUEST_SEAL         0x0020
+#define NEGOTIATE_DATAGRAM_STYLE       0x0040
+#define NEGOTIATE_USE_LM               0x0080
+#define NEGOTIATE_USE_NETWARE          0x0100
+#define NEGOTIATE_USE_NTLM             0x0200
+#define NEGOTIATE_DOMAIN_SUPPLIED      0x1000
+#define NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
+#define NEGOTIATE_THIS_IS_LOCAL_CALL   0x4000
+#define NEGOTIATE_ALWAYS_SIGN          0x8000
+
+/* challenge request flags */
+#define CHALLENGE_TARGET_IS_DOMAIN     0x10000
+#define CHALLENGE_TARGET_IS_SERVER     0x20000
+#define CHALLENGE_TARGET_IS_SHARE      0x40000
+
+/* these are marked as "extra" fields */
+#define REQUEST_INIT_RESPONSE          0x100000
+#define REQUEST_ACCEPT_RESPONSE        0x200000
+#define REQUEST_NON_NT_SESSION_KEY     0x400000
+
+
+/* String header. String data resides at the end of the request */
+typedef struct _strhdr {
+    int16_t len;               /* Length in bytes */
+    int16_t maxlen;            /* Allocated space in bytes */
+    int32_t offset;            /* Offset from start of request */
+} strhdr;
+
+/* We use this to keep data/lenght couples. Only used internally. */
+typedef struct _lstring {
+    int32_t l;                 /* length, -1 if empty */
+    char *str;                 /* the string. NULL if not initialized */
+} lstring;
+
+/* This is an header common to all signatures, it's used to discriminate
+ * among the different signature types. */
+typedef struct _ntlmhdr {
+    char signature[8];         /* "NTLMSSP" */
+    int32_t type;              /* LSWAP(0x1) */
+} ntlmhdr;
+
+/* Negotiation request sent by client */
+typedef struct _ntlm_negotiate {
+    char signature[8];         /* "NTLMSSP" */
+    int32_t type;              /* LSWAP(0x1) */
+    ntlmhdr hdr;               /* NTLM header */
+    u_int32_t flags;           /* Request flags */
+    strhdr domain;             /* Domain we wish to authenticate in */
+    strhdr workstation;                /* Client workstation name */
+    char payload[256];         /* String data */
+} ntlm_negotiate;
+
+/* Challenge request sent by server. */
+typedef struct _ntlm_challenge {
+    char signature[8];         /* "NTLMSSP" */
+    int32_t type;              /* LSWAP(0x2) */
+    strhdr target;             /* Authentication target (domain/server ...) */
+    u_int32_t flags;           /* Request flags */
+    u_char challenge[NONCE_LEN];       /* Challenge string */
+    u_int32_t context_low;     /* LS part of the server context handle */
+    u_int32_t context_high;    /* MS part of the server context handle */
+    char payload[256];         /* String data */
+} ntlm_challenge;
+
+/* Authentication request sent by client in response to challenge */
+typedef struct _ntlm_authenticate {
+    char signature[8];         /* "NTLMSSP" */
+    int32_t type;              /* LSWAP(0x3) */
+    strhdr lmresponse;         /* LANMAN challenge response */
+    strhdr ntresponse;         /* NT challenge response */
+    strhdr domain;             /* Domain to authenticate against */
+    strhdr user;               /* Username */
+    strhdr workstation;                /* Workstation name */
+    strhdr sessionkey;         /* Session key for server's use */
+    int32_t flags;             /* Request flags */
+    char payload[256 * 6];     /* String data */
+} ntlm_authenticate;
+
+const char *ntlm_make_challenge(char *domain, char *domain_controller,
+    char *challenge_nonce, int challenge_nonce_len);
+lstring ntlm_fetch_string(char *packet, int32_t length, strhdr * str);
+void ntlm_add_to_payload(char *payload, int *payload_length,
+    strhdr * hdr, char *toadd,
+    int toadd_length, int base_offset);
+
+#endif /* _NTLMAUTH_H_ */
index 8e2bfebd2f87219b2e828d2d2e31da3cf54f2aca..c5633ac2ea962bea3a48ffba4fe42a37067afd75 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: util.h,v 1.56 2000/11/04 23:04:09 hno Exp $
+ * $Id: util.h,v 1.57 2001/01/07 23:36:35 hno Exp $
  *
  * AUTHOR: Harvest Derived
  *
@@ -111,6 +111,7 @@ extern int safe_inet_addr(const char *, SIA *);
 extern time_t parse_iso3307_time(const char *buf);
 extern char *base64_decode(const char *coded);
 extern const char *base64_encode(const char *decoded);
+extern const char *base64_encode_bin(const char *data, int len);
 
 extern double xpercent(double part, double whole);
 extern int xpercentInt(double part, double whole);
index 43b13e6d7f25f5e4b896f1a91e2b1be94f07ab36..5ae7ab5cd0a668a0d95e536814e159aada4c6a2d 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  $Id: Makefile.in,v 1.47 2000/11/21 21:15:10 wessels Exp $
+#  $Id: Makefile.in,v 1.48 2001/01/07 23:36:36 hno Exp $
 #
 prefix         = @prefix@
 top_srcdir     = @top_srcdir@
@@ -43,7 +43,8 @@ UTILOBJS      = rfc1123.o \
                  $(LIBOBJS)
 REGEXOBJS      = GNUregex.o
 DLMALLOCOBJS   = dlmalloc.o
-LIBS           = libmiscutil.a @LIBREGEX@ @LIBDLMALLOC@
+NTLMAUTHOBJS = ntlmauth.o
+LIBS           = libmiscutil.a @LIBREGEX@ @LIBDLMALLOC@ libntlmauth.a
 
 CFLAGS         = $(AC_CFLAGS) $(INCLUDE)
 
@@ -66,6 +67,11 @@ libdlmalloc.a: $(DLMALLOCOBJS)
        $(AR_R) $@ $(DLMALLOCOBJS)
        $(RANLIB) $@
 
+libntlmauth.a: $(NTLMAUTHOBJS)
+       $(RM) -f $@
+       $(AR_R) $@ $(NTLMAUTHOBJS)
+       $(RANLIB) $@
+
 clean:
        -rm -f *.o $(LIBS) core
 
index 60f797b27eecf7d5ef211f0a8794e4f2470845d9..75c46d458fa21098ab9a1ec805d2550c1e44e45d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: base64.c,v 1.16 1998/10/14 02:40:25 wessels Exp $
+ * $Id: base64.c,v 1.17 2001/01/07 23:36:36 hno Exp $
  */
 
 #include "config.h"
@@ -111,3 +111,50 @@ base64_encode(const char *decoded_str)
     result[out_cnt] = '\0';    /* terminate */
     return result;
 }
+
+/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
+const char *
+base64_encode_bin(const char *data, int len)
+{
+    static char result[BASE64_RESULT_SZ];
+    int bits = 0;
+    int char_count = 0;
+    int out_cnt = 0;
+    int c;
+
+    if (!data)
+       return data;
+
+    if (!base64_initialized)
+       base64_init();
+
+    while (len-- && out_cnt < sizeof(result) - 1) {
+       c = (unsigned char) *data++;
+       bits += c;
+       char_count++;
+       if (char_count == 3) {
+           result[out_cnt++] = base64_code[bits >> 18];
+           result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
+           result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
+           result[out_cnt++] = base64_code[bits & 0x3f];
+           bits = 0;
+           char_count = 0;
+       } else {
+           bits <<= 8;
+       }
+    }
+    if (char_count != 0) {
+       bits <<= 16 - (8 * char_count);
+       result[out_cnt++] = base64_code[bits >> 18];
+       result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
+       if (char_count == 1) {
+           result[out_cnt++] = '=';
+           result[out_cnt++] = '=';
+       } else {
+           result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
+           result[out_cnt++] = '=';
+       }
+    }
+    result[out_cnt] = '\0';    /* terminate */
+    return result;
+}
diff --git a/lib/ntlmauth.c b/lib/ntlmauth.c
new file mode 100644 (file)
index 0000000..5158798
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * $Id: ntlmauth.c,v 1.1 2001/01/07 23:36:36 hno Exp $
+ *
+ * * * * * * * * Legal stuff * * * * * * *
+ *
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *   inspired by previous work by Andy Doran.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "ntlmauth.h"
+#include "util.h"              /* for base64-related stuff */
+
+/* Dumps NTLM flags to standard error for debugging purposes */
+void
+ntlm_dump_ntlmssp_flags(u_int32_t flags)
+{
+    fprintf(stderr, "flags: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+       (flags & NEGOTIATE_UNICODE ? "Unicode " : ""),
+       (flags & NEGOTIATE_ASCII ? "ASCII " : ""),
+       (flags & NEGOTIATE_REQUEST_TARGET ? "ReqTgt " : ""),
+       (flags & NEGOTIATE_REQUEST_SIGN ? "ReqSign " : ""),
+       (flags & NEGOTIATE_REQUEST_SEAL ? "ReqSeal " : ""),
+       (flags & NEGOTIATE_DATAGRAM_STYLE ? "Dgram " : ""),
+       (flags & NEGOTIATE_USE_LM ? "UseLM " : ""),
+       (flags & NEGOTIATE_USE_NETWARE ? "UseNW " : ""),
+       (flags & NEGOTIATE_USE_NTLM ? "UseNTLM " : ""),
+       (flags & NEGOTIATE_DOMAIN_SUPPLIED ? "HaveDomain " : ""),
+       (flags & NEGOTIATE_WORKSTATION_SUPPLIED ? "HaveWKS " : ""),
+       (flags & NEGOTIATE_THIS_IS_LOCAL_CALL ? "LocalCall " : ""),
+       (flags & NEGOTIATE_ALWAYS_SIGN ? "AlwaysSign " : ""),
+       (flags & CHALLENGE_TARGET_IS_DOMAIN ? "Tgt_is_domain" : ""),
+       (flags & CHALLENGE_TARGET_IS_SERVER ? "Tgt_is_server " : ""),
+       (flags & CHALLENGE_TARGET_IS_SHARE ? "Tgt_is_share " : ""),
+       (flags & REQUEST_INIT_RESPONSE ? "Req_init_response " : ""),
+       (flags & REQUEST_ACCEPT_RESPONSE ? "Req_accept_response " : ""),
+       (flags & REQUEST_NON_NT_SESSION_KEY ? "Req_nonnt_sesskey " : "")
+       );
+}
+
+#define lstring_zero(s) s.str=NULL; s.l=-1;
+
+/* fetches a string from the authentication packet.
+ * The lstring data-part points to inside the packet itself.
+ * It's up to the user to memcpy() that if the value needs to
+ * be used in any way that requires a tailing \0. (he can check whether the
+ * value is there though, in that case lstring.length==-1).
+ */
+lstring
+ntlm_fetch_string(char *packet, int32_t length, strhdr * str)
+{
+    int16_t l;                 /* length */
+    int32_t o;                 /* offset */
+    lstring rv;
+
+    lstring_zero(rv);
+
+    l = SSWAP(str->len);
+    o = WSWAP(str->offset);
+    /* debug("fetch_string(plength=%d,l=%d,o=%d)\n",length,l,o); */
+
+    if (l < 0 || l > MAX_FIELD_LENGTH || o + l > length || o == 0) {
+       /* debug("ntlmssp: insane data (l: %d, o: %d)\n", l,o); */
+       return rv;
+    }
+    rv.str = packet + o;
+    rv.l = l;
+
+    return rv;
+}
+
+/* Adds something to the payload. The caller must guarrantee that
+ * there is enough space in the payload string to accommodate the
+ * added value.
+ * payload_length and hdr will be modified as a side-effect.
+ * base_offset is the payload offset from the packet's beginning, and is
+ */
+void
+ntlm_add_to_payload(char *payload, int *payload_length,
+    strhdr * hdr, char *toadd,
+    int toadd_length, int base_offset)
+{
+
+    int l = (*payload_length);
+    memcpy(payload + l, toadd, toadd_length);
+
+    hdr->len = toadd_length;
+    hdr->maxlen = toadd_length;
+    hdr->offset = l + base_offset;     /* 48 is the base offset of the payload */
+    (*payload_length) += toadd_length;
+}
+
+
+/* prepares a base64-encode challenge packet to be sent to the client
+ * note: domain should be upper_case
+ * note: the storage type for the returned value depends on
+ *    base64_encode_bin. Currently this means static storage.
+ */
+const char *
+ntlm_make_challenge(char *domain, char *domain_controller,
+    char *challenge_nonce, int challenge_nonce_len)
+{
+    ntlm_challenge ch;
+    int pl = 0;
+    const char *encoded;
+    memset(&ch, 0, sizeof(ntlm_challenge));    /* reset */
+    memcpy(ch.signature, "NTLMSSP", 8);                /* set the signature */
+    ch.type = WSWAP(NTLM_CHALLENGE);   /* this is a challenge */
+    ntlm_add_to_payload(ch.payload, &pl, &ch.target, domain, strlen(domain),
+       NTLM_CHALLENGE_HEADER_OFFSET);
+    ch.flags = WSWAP(
+       REQUEST_NON_NT_SESSION_KEY |
+       CHALLENGE_TARGET_IS_DOMAIN |
+       NEGOTIATE_ALWAYS_SIGN |
+       NEGOTIATE_USE_NTLM |
+       NEGOTIATE_USE_LM |
+       NEGOTIATE_ASCII |
+       0
+       );
+    ch.context_low = 0;                /* check this out */
+    ch.context_high = 0;
+    memcpy(ch.challenge, challenge_nonce, challenge_nonce_len);
+    encoded = base64_encode_bin((char *) &ch, NTLM_CHALLENGE_HEADER_OFFSET + pl);
+    return encoded;
+}
index 8d0db31b68599749bc9b13c2155a43e024f9e909..d2b290d4c2eb3539633cb4cdf9877b114afaba63 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: util.c,v 1.75 2001/01/07 09:55:22 hno Exp $
+ * $Id: util.c,v 1.76 2001/01/07 23:36:36 hno Exp $
  *
  * DEBUG: 
  * AUTHOR: Harvest Derived
@@ -749,7 +749,7 @@ xitoa(int num)
 }
 
 /* A default failure notifier when the main program hasn't installed any */
-void 
+void
 default_failure_notify(const char *msg)
 {
     write(2, msg, strlen(msg));
index cac8bf47afb248b6ffcabcaff57a77b3cafdca33..50e7f11336f9d362add01c49aa108b977d1950ed 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpRequest.cc,v 1.27 2001/01/04 21:09:00 wessels Exp $
+ * $Id: HttpRequest.cc,v 1.28 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 73    HTTP Request
  * AUTHOR: Duane Wessels
@@ -55,7 +55,10 @@ void
 requestDestroy(request_t * req)
 {
     assert(req);
-    safe_free(req->body);
+    if (req->body_connection)
+       clientAbortBody(req);
+    if (req->auth_user_request)
+       authenticateAuthUserRequestUnlock(req->auth_user_request);
     safe_free(req->canonical);
     stringClean(&req->urlpath);
     httpHeaderClean(&req->header);
index e227537531aefc62bf2c4d04aacfdc8bdc5742f9..f6cf97439f43c7b587fe25ccab280aa1f6c0a15e 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.195 2000/10/20 23:50:59 hno Exp $
+#  $Id: Makefile.in,v 1.196 2001/01/07 23:36:37 hno Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -18,7 +18,7 @@ localstatedir   = @localstatedir@
 srcdir         = @srcdir@
 VPATH          = @srcdir@
 
-SUBDIRS                = fs repl
+SUBDIRS                = fs repl auth
 
 # Gotta love the DOS legacy
 #
@@ -47,6 +47,8 @@ DEFAULT_ICON_DIR      = $(sysconfdir)/icons
 DEFAULT_ERROR_DIR      = $(sysconfdir)/errors
 DEFAULT_MIB_PATH       = $(sysconfdir)/mib.txt
 
+AUTH_OBJS      = @AUTH_OBJS@
+AUTH_MODULES   = @AUTH_MODULES@
 CC             = @CC@
 MAKEDEPEND     = @MAKEDEPEND@
 INSTALL                = @INSTALL@
@@ -90,6 +92,7 @@ OBJS          = \
                access_log.o \
                acl.o \
                asn.o \
+               auth_modules.o \
                authenticate.o \
                cache_cf.o \
                CacheDigest.o \
@@ -148,7 +151,6 @@ OBJS                = \
                pconn.o \
                peer_digest.o \
                peer_select.o \
-               pump.o \
                redirect.o \
                referer.o \
                refresh.o \
@@ -208,8 +210,8 @@ $(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h
 
 $(SNMP_OBJS): ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h
 
-$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS)
-       $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(SQUID_LIBS)
+$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS)
+       $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(SQUID_LIBS)
 
 globals.o: globals.c Makefile
        $(CC) -c globals.c $(CFLAGS) -I$(srcdir) $(DEFAULTS)
@@ -298,6 +300,15 @@ $(REPL_OBJS):
 repl_modules repl/stamp:
        @sh -c "cd repl && $(MAKE) all"
 
+auth_modules.c: auth_modules.sh Makefile
+       sh $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.c
+
+auth_modules.o: auth_modules.c
+       $(CC) -c auth_modules.c $(CFLAGS) -I$(srcdir)
+
+$(AUTH_OBJS):
+       @sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`"
+
 install-mkdirs:
        -@if test ! -d $(prefix); then \
                echo "mkdir $(prefix)"; \
@@ -406,7 +417,7 @@ install-pinger:
 clean: 
        -rm -rf *.o *pure_* core $(PROGS) $(UTILS) $(CGIPROGS) $(SUID_UTILS)
        -rm -f cf_gen cf_gen_defines.h cf_parser.c cf.data globals.c string_arrays.c
-       -rm -f store_modules.c repl_modules.c squid.conf
+       -rm -f store_modules.c repl_modules.c auth_modules.c squid.conf
        @for dir in $(SUBDIRS); do \
                echo "Making $@ in $$dir..."; \
                (cd $$dir ; $(MAKE) $(MFLAGS) prefix="$(prefix)" $@) || exit 1; \
index d583bc4f6779e121ed08742ab3cd1ed1fbec58f2..a1585248c9d8c4961cf1ba635b1a6005154e0fca 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: access_log.cc,v 1.64 2001/01/02 00:09:55 wessels Exp $
+ * $Id: access_log.cc,v 1.65 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 46    Access Log
  * AUTHOR: Duane Wessels
@@ -182,10 +182,60 @@ log_quote(const char *header)
     return buf;
 }
 
+char *
+username_quote(const char *header)
+/* copy of log_quote. Bugs there will be found here */
+{
+    int c;
+    int i;
+    char *buf;
+    char *buf_cursor;
+    if (header == NULL) {
+       buf = xcalloc(1, 1);
+       *buf = '\0';
+       return buf;
+    }
+    buf = xcalloc((strlen(header) * 3) + 1, 1);
+    buf_cursor = buf;
+    /*
+     * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
+     * to prevent garbage in the logs. CR and LF are also there just in case. 
+     */
+    while ((c = *(const unsigned char *) header++) != '\0') {
+       if (c == '\r') {
+           *buf_cursor++ = '\\';
+           *buf_cursor++ = 'r';
+       } else if (c == '\n') {
+           *buf_cursor++ = '\\';
+           *buf_cursor++ = 'n';
+       } else if (c <= 0x1F
+               || c >= 0x7F
+           || c == ' ') {
+           *buf_cursor++ = '%';
+           i = c * 2;
+           *buf_cursor++ = c2x[i];
+           *buf_cursor++ = c2x[i + 1];
+       } else {
+           *buf_cursor++ = (char) c;
+       }
+    }
+    *buf_cursor = '\0';
+    return buf;
+}
+
+char *
+accessLogFormatName(const char *name)
+{
+    if (NULL == name)
+       return xcalloc(strlen(dash_str) + 1, 1);
+    return username_quote(name);
+}
+
 static void
 accessLogSquid(AccessLogEntry * al)
 {
     const char *client = NULL;
+    char *user = NULL;
     if (Config.onoff.log_fqdn)
        client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
     if (client == NULL)
@@ -200,24 +250,28 @@ accessLogSquid(AccessLogEntry * al)
        al->cache.size,
        al->private.method_str,
        al->url,
-       al->cache.ident,
+       (user = accessLogFormatName(al->cache.authuser ?
+               al->cache.authuser : al->cache.rfc931)),
        al->hier.ping.timedout ? "TIMEOUT_" : "",
        hier_strings[al->hier.code],
        al->hier.host,
        al->http.content_type);
+    safe_free(user);
 }
 
 static void
 accessLogCommon(AccessLogEntry * al)
 {
     const char *client = NULL;
+    char *user = NULL;
     if (Config.onoff.log_fqdn)
        client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
     if (client == NULL)
        client = inet_ntoa(al->cache.caddr);
-    logfilePrintf(logfile, "%s %s - [%s] \"%s %s HTTP/%d.%d\" %d %d %s:%s",
+    logfilePrintf(logfile, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %d %s:%s",
        client,
-       al->cache.ident,
+       accessLogFormatName(al->cache.rfc931),
+       (user = accessLogFormatName(al->cache.authuser)),
        mkhttpdlogtime(&squid_curtime),
        al->private.method_str,
        al->url,
@@ -226,25 +280,18 @@ accessLogCommon(AccessLogEntry * al)
        al->cache.size,
        log_tags[al->cache.code],
        hier_strings[al->hier.code]);
+    safe_free(user);
 }
 
 void
 accessLogLog(AccessLogEntry * al)
 {
-    LOCAL_ARRAY(char, ident_buf, USER_IDENT_SZ);
-
     if (LogfileStatus != LOG_ENABLE)
        return;
     if (al->url == NULL)
        al->url = dash_str;
     if (!al->http.content_type || *al->http.content_type == '\0')
        al->http.content_type = dash_str;
-    if (!al->cache.ident || *al->cache.ident == '\0') {
-       al->cache.ident = dash_str;
-    } else {
-       xstrncpy(ident_buf, rfc1738_escape(al->cache.ident), USER_IDENT_SZ);
-       al->cache.ident = ident_buf;
-    }
     if (al->icp.opcode)
        al->private.method_str = icp_opcode_str[al->icp.opcode];
     else
index 9685b9c4fad6f5ce7ad25b57ba72b074941cce60..9f7b317bc6571204ac4e6c64ca09cb5f17e49444 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: acl.cc,v 1.235 2001/01/07 20:11:16 hno Exp $
+ * $Id: acl.cc,v 1.236 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 28    Access Control
  * AUTHOR: Duane Wessels
@@ -38,7 +38,6 @@
 
 static int aclFromFile = 0;
 static FILE *aclFile;
-static hash_table *proxy_auth_cache = NULL;
 
 static void aclParseDomainList(void *curlist);
 static void aclParseUserList(void **current);
@@ -53,7 +52,8 @@ static char *strtokFile(void);
 static void aclDestroyAclList(acl_list * list);
 static void aclDestroyTimeList(acl_time_data * data);
 static void aclDestroyIntRange(intrange *);
-static FREE aclFreeProxyAuthUser;
+static void aclLookupProxyAuthStart(aclCheck_t * checklist);
+static void aclLookupProxyAuthDone(void *data, char *result);
 static struct _acl *aclFindByName(const char *name);
 static int aclMatchAcl(struct _acl *, aclCheck_t *);
 static int aclMatchIntegerRange(intrange * data, int i);
@@ -76,8 +76,6 @@ static IPH aclLookupDstIPDone;
 static IPH aclLookupDstIPforASNDone;
 static FQDNH aclLookupSrcFQDNDone;
 static FQDNH aclLookupDstFQDNDone;
-static void aclLookupProxyAuthStart(aclCheck_t * checklist);
-static void aclLookupProxyAuthDone(void *data, char *result);
 static wordlist *aclDumpIpList(void *);
 static wordlist *aclDumpDomainList(void *data);
 static wordlist *aclDumpTimeSpecList(acl_time_data *);
@@ -101,6 +99,7 @@ static wordlist *aclDumpArpList(void *);
 static SPLAYCMP aclArpCompare;
 static SPLAYWALKEE aclDumpArpListWalkee;
 #endif
+static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char *MatchParam);
 
 static char *
 strtokFile(void)
@@ -788,19 +787,25 @@ aclParseAclLine(acl ** head)
        aclParseMethodList(&A->data);
        break;
     case ACL_PROXY_AUTH:
-       aclParseUserList(&A->data);
-       if (!proxy_auth_cache) {
-           /* First time around, 7921 should be big enough */
-           proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-           assert(proxy_auth_cache);
+       if (authenticateSchemeCount() == 0) {
+           debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
+because no authentication schemes were compiled.\n", A->cfgline);
+       } else if (authenticateActiveSchemeCount() == 0) {
+           debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
+because no authentication schemes are fully configured.\n", A->cfgline);
+       } else {
+           aclParseUserList(&A->data);
        }
        break;
     case ACL_PROXY_AUTH_REGEX:
-       aclParseRegexList(&A->data);
-       if (!proxy_auth_cache) {
-           /* First time around, 7921 should be big enough */
-           proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-           assert(proxy_auth_cache);
+       if (authenticateSchemeCount() == 0) {
+           debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
+because no authentication schemes were compiled.\n", A->cfgline);
+       } else if (authenticateActiveSchemeCount() == 0) {
+           debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
+because no authentication schemes are fully configured.\n", A->cfgline);
+       } else {
+           aclParseRegexList(&A->data);
        }
        break;
 #if SQUID_SNMP
@@ -1081,205 +1086,229 @@ aclMatchUser(void *proxyauth_acl, char *user)
     return !splayLastResult;
 }
 
+/* ACL result caching routines */
+
+/*
+ * we lookup an acl's cached results, and if we cannot find the acl being 
+ * checked we check it and cache the result. This function is deliberatly 
+ * generic to support caching of multiple acl types (but it needs to be more
+ * generic still....
+ * The Match Param and the cache MUST be tied together by the calling routine.
+ * You have been warned :-]
+ * Also only Matchxxx that are of the form (void *, void *) can be used.
+ * probably some ugly overloading _could_ be done but I'll leave that as an
+ * exercise for the reader. Note that caching of time based acl's is not
+ * wise due to no expiry occuring to the cache entries until the user expires
+ * or a reconfigure takes place. 
+ * RBC
+ */
 static int
-aclDecodeProxyAuth(const char *proxy_auth, char **user, char **password, char *buf, size_t bufsize)
-{
-    char *sent_auth;
-    char *cleartext;
-    if (proxy_auth == NULL)
-       return 0;
-    debug(28, 6) ("aclDecodeProxyAuth: header = '%s'\n", proxy_auth);
-    if (strncasecmp(proxy_auth, "Basic ", 6) != 0) {
-       debug(28, 1) ("aclDecodeProxyAuth: Unsupported proxy-auth sheme, '%s'\n", proxy_auth);
-       return 0;
+aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data,
+    char *MatchParam)
+{
+    int matchrv;
+    acl_proxy_auth_match_cache *auth_match;
+    dlink_node *link;
+    link = cache->head;
+    while (link) {
+       auth_match = link->data;
+       if (auth_match->acl_data == data) {
+           debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%d'\n",
+               data);
+           return auth_match->matchrv;
+       }
+       link = link->next;
     }
-    proxy_auth += 6;           /* "Basic " */
-    /* Trim leading whitespace before decoding */
-    while (xisspace(*proxy_auth))
-       proxy_auth++;
-    sent_auth = xstrdup(proxy_auth);   /* username and password */
-    /* Trim trailing \n before decoding */
-    strtok(sent_auth, "\n");
-    cleartext = uudecode(sent_auth);
-    xfree(sent_auth);
-    /*
-     * Don't allow NL or CR in the credentials.
-     * Oezguer Kesim <oec@codeblau.de>
-     */
-    strtok(cleartext, "\r\n");
-    debug(28, 6) ("aclDecodeProxyAuth: cleartext = '%s'\n", cleartext);
-    xstrncpy(buf, cleartext, bufsize);
-    xfree(cleartext);
-    /* Trim leading whitespace after decoding */
-    while (xisspace(*buf))
-       buf++;
-    *user = buf;
-    if ((*password = strchr(*user, ':')) != NULL)
-       *(*password)++ = '\0';
-    if (*password == NULL) {
-       debug(28, 1) ("aclDecodeProxyAuth: no password in proxy authorization header '%s'\n", proxy_auth);
-       return 0;
+    auth_match = NULL;
+    /* match the user in the acl. They are not cached. */
+    switch (acltype) {
+    case ACL_PROXY_AUTH:
+       matchrv = aclMatchUser(data, MatchParam);
+       break;
+    case ACL_PROXY_AUTH_REGEX:
+       matchrv = aclMatchRegex(data, MatchParam);
+    default:
+       /* This is a fatal to ensure that aclCacheMatchAcl calls are _only_
+        * made for supported acl types */
+       fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
+       return 0;               /* NOTREACHED */
     }
-    if (**password == '\0') {
-       debug(28, 1) ("aclDecodeProxyAuth: Disallowing empty password,"
-           "user is '%s'\n", *user);
-       return 0;
+    auth_match = memAllocate(MEM_ACL_PROXY_AUTH_MATCH);
+    auth_match->matchrv = matchrv;
+    auth_match->acl_data = data;
+    dlinkAddTail(auth_match, &auth_match->link, cache);
+    return matchrv;
+}
+
+void
+aclCacheMatchFlush(dlink_list * cache)
+{
+    acl_proxy_auth_match_cache *auth_match;
+    dlink_node *link, *tmplink;
+    link = cache->head;
+    while (link) {
+       auth_match = link->data;
+       tmplink = link;
+       link = link->next;
+       dlinkDelete(tmplink, cache);
+       memFree(auth_match, MEM_ACL_PROXY_AUTH_MATCH);
     }
-    return 1;
 }
 
-/* aclMatchProxyAuth can return three exit codes:
- * 0 : user denied access
- * 1 : user validated OK
- * -1 : check the password for this user via an external authenticator
- * -2 : invalid Proxy-authorization: header;
- * ask for Proxy-Authorization: header
+/* aclMatchProxyAuth can return four exit codes:
+ * 0 : Authenticated OK, Authorisation for this ACL failed. 
+ * 1 : Authenticated OK, Authorisation OK.
+ * -1 : send data to an external authenticator
+ * -2 : send data to the client
  */
-
 static int
-aclMatchProxyAuth(void *data, const char *proxy_auth, acl_proxy_auth_user * auth_user, aclCheck_t * checklist, squid_acl acltype)
+aclMatchProxyAuth(void *data, http_hdr_type headertype,
+    auth_user_request_t * auth_user_request, aclCheck_t * checklist, squid_acl acltype)
 {
     /* checklist is used to register user name when identified, nothing else */
-    LOCAL_ARRAY(char, login_buf, USER_IDENT_SZ);
-    char *user, *password;
-
-    if (!aclDecodeProxyAuth(proxy_auth, &user, &password, login_buf, sizeof(login_buf)))
-       /* No or invalid Proxy-Auth header */
-       return -2;
+    const char *proxy_auth;
+    /* consistent parameters ? */
+    assert(auth_user_request == checklist->auth_user_request);
+
+    /* General program flow in proxy_auth acls
+     * 1. Consistency checks: are we getting sensible data
+     * 2. Call the authenticate* functions to establish a authenticated user
+     * 4. look up the username in acltype (and cache the result against the 
+     *     username
+     */
 
-    debug(28, 5) ("aclMatchProxyAuth: checking user '%s'\n", user);
+    assert(headertype != 0);
+    proxy_auth = httpHeaderGetStr(&checklist->request->header, headertype);
 
-    if (auth_user) {
+    if (checklist->conn == NULL) {
+       debug(28, 1) ("aclMatchProxyAuth: no connection data, cannot process authentication\n");
        /*
-        * This should be optimized to a boolean argument indicating that the
-        * password is invalid, instead of passing full acl_proxy_auth_user
-        * structures, and all messing with checklist->proxy_auth should
-        * be restricted the functions that deal with the authenticator.
+        * deny access: clientreadrequest requires conn data, and it is always
+        * compiled in so we should have it too.
         */
-       assert(auth_user == checklist->auth_user);
-       checklist->auth_user = NULL;    /* get rid of that special reference */
-       /* Check result from external validation */
-       if (auth_user->passwd_ok != 1) {
-           /* password was checked but did not match */
-           assert(auth_user->passwd_ok == 0);
-           debug(28, 4) ("aclMatchProxyAuth: authentication failed for user '%s'\n",
-               user);
-           aclFreeProxyAuthUser(auth_user);
-           /*
-            * copy username to request for logging on client-side
-            * unless ident is known (do not override ident with
-            * false proxy auth names)
-            */
-           if (!*checklist->request->user_ident)
-               xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ);
-           return -2;
-       } else {
-           /* password was checked and did match */
-           debug(28, 4) ("aclMatchProxyAuth: user '%s' validated OK\n", user);
-           /* store validated user in hash, after filling in expiretime */
-           xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ);
-           auth_user->expiretime = current_time.tv_sec + Config.authenticateTTL;
-           auth_user->ip_expiretime = squid_curtime + Config.authenticateIpTTL;
-           auth_user->ipaddr = checklist->src_addr;
-           hash_join(proxy_auth_cache, &auth_user->hash);
-           /* Continue checking below, as normal */
+       return 0;
+    }
+    if (((proxy_auth == NULL) && (checklist->conn->auth_type == AUTH_UNKNOWN)) || (checklist->conn->auth_type == AUTH_BROKEN)) {
+       /* no header or authentication failed/got corrupted - restart */
+       checklist->conn->auth_type = AUTH_UNKNOWN;
+       debug(28, 4) ("aclMatchProxyAuth: broken auth or no proxy_auth header. Requesting auth header.\n");
+       /* something wrong with the AUTH credentials. Force a new attempt */
+       checklist->auth_user_request = NULL;
+       checklist->conn->auth_user_request = NULL;
+       if (auth_user_request) {
+           /* unlock the ACL lock */
+           authenticateAuthUserRequestUnlock(auth_user_request);
        }
+       return -2;
     }
-    /* see if we already know this user */
-    auth_user = hash_lookup(proxy_auth_cache, user);
-
-    if (!auth_user) {
-       /* user not yet known, ask external authenticator */
-       debug(28, 4) ("aclMatchProxyAuth: user '%s' not yet known\n", user);
-       return -1;
-    } else if ((0 == strcmp(auth_user->passwd, password)) &&
-       (auth_user->expiretime > current_time.tv_sec)) {
-       if (checklist->src_addr.s_addr == auth_user->ipaddr.s_addr
-           || auth_user->ip_expiretime <= squid_curtime) {
-           /* user already known and valid */
-           debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n",
-               user);
-           /* Update IP ttl */
-           auth_user->ip_expiretime = squid_curtime + Config.authenticateIpTTL;
-           auth_user->ipaddr = checklist->src_addr;
-           /* copy username to request for logging on client-side */
-           xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ);
-           switch (acltype) {
-           case ACL_PROXY_AUTH:
-               return aclMatchUser(data, user);
-           case ACL_PROXY_AUTH_REGEX:
-               return aclMatchRegex(data, user);
-           default:
-               fatal("aclMatchProxyAuth: unknown ACL type");
-               return 0;       /* NOTREACHED */
+    /* we have a proxy auth header and as far as we know this connection has
+     * not had bungled connection oriented authentication happen on it. */
+    debug(28, 9) ("aclMatchProxyAuth: header %s.\n", proxy_auth);
+    if (auth_user_request == NULL) {
+       debug(28, 9) ("aclMatchProxyAuth: This is a new request on FD:%d\n", checklist->conn->fd);
+       if ((!checklist->request->auth_user_request) && (checklist->conn->auth_type == AUTH_UNKNOWN)) {
+           /* beginning of a new request check */
+           debug(28, 4) ("aclMatchProxyAuth: no connection authentication type\n");
+           if (!authenticateValidateUser(auth_user_request = authenticateGetAuthUser(proxy_auth))) {
+               /* the decode might have left a username for logging, or a message to
+                * the user */
+               if (auth_user_request) {
+                   /* lock the user for the request structure link */
+                   authenticateAuthUserRequestLock(auth_user_request);
+                   checklist->request->auth_user_request = auth_user_request;
+                   /* unlock the ACL reference. */
+                   authenticateAuthUserRequestUnlock(auth_user_request);
+               }
+               return -2;
            }
+           /* the user_request comes prelocked for the caller to GetAuthUser (us) */
+       } else if (checklist->request->auth_user_request) {
+           auth_user_request = checklist->request->auth_user_request;
+           /* lock the user request for this ACL processing */
+           authenticateAuthUserRequestLock(auth_user_request);
        } else {
-           if (Config.onoff.authenticateIpTTLStrict) {
-               /* Access from some other IP address than the one owning
-                * this user ID. Deny access
-                */
-               debug(28, 1) ("aclMatchProxyAuth: user '%s' tries to use multple IP addresses!\n", user);
-               return 0;
+           if (checklist->conn->auth_user_request != NULL) {
+               auth_user_request = checklist->conn->auth_user_request;
+               /* lock the user request for this ACL processing */
+               authenticateAuthUserRequestLock(auth_user_request);
            } else {
-               /* user has switched to another IP addr */
-               debug(28, 1) ("aclMatchProxyAuth: user '%s' has changed IP address\n", user);
-               /* remove this user from the hash, making him unknown */
-               hash_remove_link(proxy_auth_cache, (hash_link *) auth_user);
-               aclFreeProxyAuthUser(auth_user);
-               /* require the user to reauthenticate */
+               /* failed connection based authentication */
+               debug(28, 4) ("aclMatchProxyAuth: Aauth user request %d conn-auth user request %d conn type %d authentication failed.\n", auth_user_request, checklist->conn->auth_user_request, checklist->conn->auth_type);
                return -2;
            }
        }
-    } else {
-       /* password mismatch/timeout */
-       debug(28, 4) ("aclMatchProxyAuth: user '%s' password mismatch/timeout\n",
-           user);
-       /* remove this user from the hash, making him unknown */
-       hash_remove_link(proxy_auth_cache, (hash_link *) auth_user);
-       aclFreeProxyAuthUser(auth_user);
-       /* ask the external authenticator in case the password is changed */
-       /* wrong password will be trapped above so this does not loop */
-       return -1;
     }
-    /* NOTREACHED */
+    /* Clear the reference in the checklist */
+    checklist->auth_user_request = NULL;
+    if (!authenticateUserAuthenticated(auth_user_request)) {
+       /* User not logged in. Log them in */
+       authenticateAuthUserRequestSetIp(auth_user_request, checklist->src_addr);
+       authenticateAuthenticateUser(auth_user_request, checklist->request, checklist->conn, headertype);
+       switch (authenticateDirection(auth_user_request)) {
+       case 1:
+           /* this ACL check is finished. Unlock. */
+           authenticateAuthUserRequestUnlock(auth_user_request);
+           return -2;
+       case -1:
+           /* we are partway through authentication within squid
+            * store the auth_user for the callback to here */
+           checklist->auth_user_request = auth_user_request;
+           /* we will be called back here. Do not Unlock */
+           return -1;
+       case -2:
+           /* this ACL check is finished. Unlock. */
+           authenticateAuthUserRequestUnlock(auth_user_request);
+           return -2;
+       }                       /* on 0 the authentication is finished - fallthrough */
+       /* See of user authentication failed for some reason */
+       if (!authenticateUserAuthenticated(auth_user_request)) {
+           if ((!checklist->rfc931[0]) &&
+               (authenticateUserRequestUsername(auth_user_request))) {
+               if (!checklist->request->auth_user_request) {
+                   /* lock the user for the request structure link */
+                   authenticateAuthUserRequestLock(auth_user_request);
+                   checklist->request->auth_user_request = auth_user_request;
+               }
+           }
+           /* this ACL check is finished. Unlock. */
+           authenticateAuthUserRequestUnlock(auth_user_request);
+           return -2;
 
+       }
+    }
+    /* User authenticated ok */
+    assert(authenticateUserAuthenticated(auth_user_request));
+
+    /* copy username to request for logging on client-side */
+    /* the credentials are correct at this point */
+    if (!checklist->request->auth_user_request) {
+       /* lock the user for the request structure link */
+       authenticateAuthUserRequestLock(auth_user_request);
+       checklist->request->auth_user_request = auth_user_request;
+    }
+    if (authenticateCheckAuthUserIP(checklist->src_addr, auth_user_request)) {
+       /* Once the match is completed we have finished with the
+        * auth_user structure */
+       /* this ACL check completed */
+       authenticateAuthUserRequestUnlock(auth_user_request);
+       /* check to see if we have matched the user-acl before */
+       return aclCacheMatchAcl(&auth_user_request->auth_user->proxy_match_cache,
+           acltype, data, authenticateUserRequestUsername(auth_user_request));
+    }
+    /* this acl check completed */
+    authenticateAuthUserRequestUnlock(auth_user_request);
+    return 0;
 }
 
 static void
 aclLookupProxyAuthStart(aclCheck_t * checklist)
 {
-    LOCAL_ARRAY(char, login_buf, USER_IDENT_SZ);
-    const char *proxy_auth;
-    char *user, *password;
-    int ok;
-    acl_proxy_auth_user *auth_user;
-    assert(!checklist->auth_user);
-    if (!checklist->request->flags.accelerated) {
-       /* Proxy auth on proxy requests */
-       proxy_auth = httpHeaderGetStr(&checklist->request->header,
-           HDR_PROXY_AUTHORIZATION);
-    } else {
-       /* WWW auth on accelerated requests */
-       proxy_auth = httpHeaderGetStr(&checklist->request->header,
-           HDR_AUTHORIZATION);
-    }
-    ok = aclDecodeProxyAuth(proxy_auth, &user, &password, login_buf,
-       sizeof(login_buf));
-    /*
-     * if aclDecodeProxyAuth() fails, the same call should have failed
-     * in aclMatchProxyAuth, and we should never get this far.
-     */
-    assert(ok);
-    debug(28, 4) ("aclLookupProxyAuthStart: going to ask authenticator on %s\n", user);
-    /* we must still check this user's password */
-    auth_user = memAllocate(MEM_ACL_PROXY_AUTH_USER);
-    auth_user->hash.key = xstrdup(user);
-    auth_user->passwd = xstrdup(password);
-    auth_user->passwd_ok = -1;
-    auth_user->expiretime = -1;
-    checklist->auth_user = auth_user;
-    authenticateStart(checklist->auth_user, aclLookupProxyAuthDone,
-       checklist);
+    auth_user_request_t *auth_user_request;
+    assert(checklist->auth_user_request != NULL);      /* this is created for us */
+    auth_user_request = checklist->auth_user_request;
+
+    assert(authenticateValidateUser(auth_user_request));
+    authenticateStart(auth_user_request, aclLookupProxyAuthDone, checklist);
 }
 
 static int
@@ -1378,6 +1407,7 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist)
     const char *header;
     const char *browser;
     int k;
+    http_hdr_type headertype;
     if (!ae)
        return 0;
     switch (ae->type) {
@@ -1505,16 +1535,16 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist)
        /* NOTREACHED */
 #if USE_IDENT
     case ACL_IDENT:
-       if (checklist->ident[0]) {
-           return aclMatchUser(ae->data, checklist->ident);
+       if (checklist->rfc931[0]) {
+           return aclMatchUser(ae->data, checklist->rfc931);
        } else {
            checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
            return 0;
        }
        /* NOTREACHED */
     case ACL_IDENT_REGEX:
-       if (checklist->ident[0]) {
-           return aclMatchRegex(ae->data, checklist->ident);
+       if (checklist->rfc931[0]) {
+           return aclMatchRegex(ae->data, checklist->rfc931);
        } else {
            checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
            return 0;
@@ -1539,48 +1569,39 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist)
            return -1;
        } else if (!r->flags.accelerated) {
            /* Proxy authorization on proxy requests */
-           header = httpHeaderGetStr(&checklist->request->header,
-               HDR_PROXY_AUTHORIZATION);
+           headertype = HDR_PROXY_AUTHORIZATION;
        } else if (r->flags.internal) {
            /* WWW authorization on accelerated internal requests */
-           header = httpHeaderGetStr(&checklist->request->header,
-               HDR_AUTHORIZATION);
+           headertype = HDR_AUTHORIZATION;
        } else {
 #if AUTH_ON_ACCELERATION
            /* WWW authorization on accelerated requests */
-           header = httpHeaderGetStr(&checklist->request->header,
-               HDR_AUTHORIZATION);
+           headertype = HDR_AUTHORIZATION;
 #else
            debug(28, 1) ("aclMatchAcl: proxy_auth %s not applicable on accelerated requests.\n", ae->name);
            return -1;
 #endif
        }
-       /*
-        * Register that we used the proxy authentication header so that
-        * it is not forwarded to the next proxy
-        */
-       r->flags.used_proxy_auth = 1;
-       /* Check the password */
-       switch (aclMatchProxyAuth(ae->data,
-               header,
-               checklist->auth_user,
-               checklist,
-               ae->type)) {
+       /* Check the credentials */
+       switch (aclMatchProxyAuth(ae->data, headertype,
+               checklist->auth_user_request, checklist, ae->type)) {
        case 0:
-           /* Correct password, but was not allowed in this ACL */
+           debug(28, 4) ("aclMatchAcl: returning  0 user authenticated but not authorised.\n");
+           /* Authenticated but not Authorised for this ACL */
            return 0;
        case 1:
-           /* user validated OK */
+           debug(28, 4) ("aclMatchAcl: returning  1 user authenticated and authorised.\n");
+           /* Authenticated and Authorised for this ACL */
            return 1;
        case -2:
-           /* no such user OR we need a proxy authentication header */
+           debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n");
+           /* Authentication credentials invalid or missing. */
+           /* Or partway through NTLM handshake. A proxy_Authenticate header
+            * gets sent to the client. */
            checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
-           /*
-            * XXX This is a bit oddly done.. should perhaps use different
-            * return codes here
-            */
            return 0;
        case -1:
+           debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n");
            /*
             * we need to validate the password
             */
@@ -1713,14 +1734,17 @@ aclCheck(aclCheck_t * checklist)
                checklist);
            return;
        } else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
-           debug(28, 3) ("aclCheck: checking password via authenticator\n");
+           debug(28, 3)
+               ("aclCheck: checking password via authenticator\n");
            aclLookupProxyAuthStart(checklist);
            checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING;
            return;
        } else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
-           /* Special case. Client is required to resend the request
-            * with authentication. The request is denied.
+           /* Client is required to resend the request with correct authentication
+            * credentials. (This may be part of a stateful auth protocol.
+            * The request is denied.
             */
+           debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n");
            allow = ACCESS_REQ_PROXY_AUTH;
            match = -1;
        }
@@ -1787,6 +1811,9 @@ aclCheckCallback(aclCheck_t * checklist, allow_t answer)
     cbdataUnlock(checklist->callback_data);
     checklist->callback = NULL;
     checklist->callback_data = NULL;
+    /* XXX: this assert is here to check for misbehaved acl authentication code. 
+     * It can probably go sometime soon. */
+    assert(checklist->auth_user_request == NULL);
     aclChecklistFree(checklist);
 }
 
@@ -1796,17 +1823,19 @@ aclLookupIdentDone(const char *ident, void *data)
 {
     aclCheck_t *checklist = data;
     if (ident) {
-       xstrncpy(checklist->ident, ident, sizeof(checklist->ident));
-       xstrncpy(checklist->request->user_ident, ident, sizeof(checklist->request->user_ident));
+       xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
+#if DONT
+       xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ);
+#endif
     } else {
-       xstrncpy(checklist->ident, "-", sizeof(checklist->ident));
+       xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ);
     }
     /*
      * Cache the ident result in the connection, to avoid redoing ident lookup
      * over and over on persistent connections
      */
-    if (cbdataValid(checklist->conn) && !checklist->conn->ident[0])
-       xstrncpy(checklist->conn->ident, checklist->ident, sizeof(checklist->conn->ident));
+    if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0])
+       xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ);
     aclCheck(checklist);
 }
 #endif
@@ -1847,17 +1876,22 @@ static void
 aclLookupProxyAuthDone(void *data, char *result)
 {
     aclCheck_t *checklist = data;
+    auth_user_request_t *auth_user_request;
     checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
-    debug(28, 4) ("aclLookupProxyAuthDone: result = %s\n",
-       result ? result : "NULL");
-    if (NULL == result)
-       checklist->auth_user->passwd_ok = 0;
-    else if (0 == strncasecmp(result, "OK", 2))
-       checklist->auth_user->passwd_ok = 1;
-    else {
-       if (strlen(result) > sizeof("ERR "))
-           checklist->auth_user->message = xstrdup(result + 4);
-       checklist->auth_user->passwd_ok = 0;
+    if (result != NULL)
+       fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and if that doesn't work, report a bug to the squid developers.\n");
+    /* state info check */
+    assert(checklist->conn != NULL);
+    auth_user_request = checklist->auth_user_request;
+    if (!authenticateValidateUser(auth_user_request)) {
+       /* credentials could not be checked either way
+        * restart the whole process */
+       checklist->conn->auth_user_request = NULL;
+       checklist->conn->auth_type = AUTH_BROKEN;
+       checklist->auth_user_request = NULL;
+       authenticateAuthUserRequestUnlock(auth_user_request);
+       aclCheck(checklist);
+       return;
     }
     aclCheck(checklist);
 }
@@ -1886,9 +1920,9 @@ aclChecklistCreate(const acl_access * A,
        checklist->state[i] = ACL_LOOKUP_NONE;
 #if USE_IDENT
     if (ident)
-       xstrncpy(checklist->ident, ident, USER_IDENT_SZ);
+       xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
 #endif
-    checklist->auth_user = NULL;       /* init to NULL */
+    checklist->auth_user_request = NULL;
     return checklist;
 }
 
@@ -1933,15 +1967,6 @@ aclDestroyRegexList(relist * data)
     }
 }
 
-static void
-aclFreeProxyAuthUser(void *data)
-{
-    acl_proxy_auth_user *u = data;
-    xfree(u->hash.key);
-    xfree(u->passwd);
-    memFree(u, MEM_ACL_PROXY_AUTH_USER);
-}
-
 static void
 aclFreeIpData(void *p)
 {
diff --git a/src/auth/Makefile.in b/src/auth/Makefile.in
new file mode 100644 (file)
index 0000000..0d11351
--- /dev/null
@@ -0,0 +1,36 @@
+#  Makefile for authentication modules in the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:42 hno Exp $
+#
+
+SUBDIRS                = @AUTH_MODULES@
+OUTLIBS                = @AUTH_LIBS@
+
+all install:
+       @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \
+           sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \
+        done; 
+
+$(OUTLIBS):
+       @sh -c "cd `basename $@ .a` && $(MAKE) $(MFLAGS) ../$@"
+
+clean:
+       -rm -f *.a stamp
+       -for dir in *; do \
+            if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1;\
+            fi; \
+        done
+
+distclean:
+       -rm -f *.a Makefile
+       -for dir in *; do \
+            if [ -f $$dir/Makefile ]; then \
+                sh -c "cd $$dir && $(MAKE) $(MFLAGS) distclean"; \
+            fi; \
+        done
+
+.DEFAULT:
+       @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \
+           sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \
+        done
diff --git a/src/auth/basic/Makefile.in b/src/auth/basic/Makefile.in
new file mode 100644 (file)
index 0000000..60c2e2c
--- /dev/null
@@ -0,0 +1,71 @@
+#
+#  Makefile for the basic authenticcation scheme modulefor the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:43 hno Exp $
+#
+
+AUTH           = basic
+
+SUBDIRS                = helpers
+
+
+top_srcdir     = @top_srcdir@
+VPATH          = @srcdir@
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+AR_R           = @AR_R@
+RANLIB         = @RANLIB@
+AC_CFLAGS      = @CFLAGS@
+SHELL          = /bin/sh
+
+INCLUDE                = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+
+OUT            = ../$(AUTH).a
+
+OBJS           = \
+               auth_basic.o
+
+
+all install: $(OUT)
+       @for dir in $(SUBDIRS); do \
+       if [ -f $$dir/Makefile ]; then \
+              sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+       fi; \
+       done;
+
+$(OUT): $(OBJS)
+       @rm -f ../stamp
+       $(AR_R) $(OUT) $(OBJS)
+       $(RANLIB) $(OUT)
+
+$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h
+
+.c.o:
+       @rm -f ../stamp
+       $(CC) $(CFLAGS) -c $<
+
+clean: 
+       -rm -rf *.o *pure_* core ../$(AUTH).a
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) clean"; \
+           fi; \
+       done
+
+distclean:     clean
+       -rm -f Makefile
+       -rm -f Makefile.bak
+       -rm -f tags
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) distclean"; \
+           fi; \
+       done
+
+tags:
+       ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch]
+
+depend:
+       $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c
diff --git a/src/auth/basic/auth_basic.cc b/src/auth/basic/auth_basic.cc
new file mode 100644 (file)
index 0000000..31820db
--- /dev/null
@@ -0,0 +1,640 @@
+
+/*
+ * $Id: auth_basic.cc,v 1.1 2001/01/07 23:36:43 hno Exp $
+ *
+ * DEBUG: section 29    Authenticator
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_basic.h"
+
+static void
+authenticateStateFree(authenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* Basic Scheme */
+
+static HLPCB authenticateBasicHandleReply;
+static AUTHSACTIVE authenticateBasicActive;
+static AUTHSAUTHED authenticateBasicAuthenticated;
+static AUTHSAUTHUSER authenticateBasicAuthenticateUser;
+static AUTHSDIRECTION authenticateBasicDirection;
+static AUTHSDECODE authenticateBasicDecodeAuth;
+static AUTHSDUMP authBasicCfgDump;
+static AUTHSFIXERR authenticateBasicFixErrorHeader;
+static AUTHSFREE authenticateBasicFreeUser;
+static AUTHSFREECONFIG authBasicFreeConfig;
+static AUTHSPARSE authBasicParse;
+static AUTHSINIT authBasicInit;
+static AUTHSSTART authenticateBasicStart;
+static AUTHSSTATS authenticateBasicStats;
+static AUTHSUSERNAME authenticateBasicUsername;
+static AUTHSSHUTDOWN authBasicDone;
+
+static helper *basicauthenticators = NULL;
+
+static auth_basic_config *basicConfig = NULL;
+
+static int authbasic_initialised = 0;
+MemPool *basic_data_pool = NULL;
+
+/*
+ *
+ * Private Functions
+ *
+ */
+
+void
+authBasicDone(void)
+{
+//    memPoolDestroy(ufs_state_pool);
+    if (basicauthenticators)
+       helperShutdown(basicauthenticators);
+    authbasic_initialised = 0;
+    if (!shutting_down)
+       return;
+    helperFree(basicauthenticators);
+    basicauthenticators = NULL;
+    memPoolDestroy(basic_data_pool);
+}
+
+void
+authSchemeSetup_basic(authscheme_entry_t * authscheme)
+{
+    assert(!authbasic_initialised);
+    authscheme->Active = authenticateBasicActive;
+    authscheme->parse = authBasicParse;
+    authscheme->dump = authBasicCfgDump;
+    authscheme->init = authBasicInit;
+    authscheme->authAuthenticate = authenticateBasicAuthenticateUser;
+    authscheme->authenticated = authenticateBasicAuthenticated;
+    authscheme->authFixHeader = authenticateBasicFixErrorHeader;
+    authscheme->FreeUser = authenticateBasicFreeUser;
+    authscheme->freeconfig = authBasicFreeConfig;
+    authscheme->authStart = authenticateBasicStart;
+    authscheme->authStats = authenticateBasicStats;
+    authscheme->authUserUsername = authenticateBasicUsername;
+    authscheme->getdirection = authenticateBasicDirection;
+    authscheme->oncloseconnection = NULL;
+    authscheme->decodeauth = authenticateBasicDecodeAuth;
+    authscheme->donefunc = authBasicDone;
+}
+
+int
+authenticateBasicActive()
+{
+#if 0
+    if (authbasic_initialised)
+       return 1;
+    else
+       return 0;
+#endif
+    if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) &&
+       (basicConfig->authenticateChildren != 0) && (basicConfig->basicAuthRealm != NULL))
+       return 1;
+    return 0;
+}
+
+int
+authenticateBasicAuthenticated(auth_user_request_t * auth_user_request)
+{
+    basic_data *basic_auth = auth_user_request->auth_user->scheme_data;
+    if ((auth_user_request->auth_user->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime))
+       return 1;
+    debug(29, 4) ("User not authenticated or credentials need rechecking.\n");
+    return 0;
+}
+
+int
+authenticateBasiccmpUsername(basic_data * u1, basic_data * u2)
+{
+    return strcmp(u1->username, u2->username);
+}
+
+/* log a basic user in
+ */
+static void
+authenticateBasicAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+#if 0
+    auth_user_hash_pointer *usernamehash, *proxy_auth_hash = NULL;
+#endif
+    auth_user_t *auth_user;
+    basic_data *basic_auth;
+#if 0
+//, *temp_auth;
+    const char *proxy_auth;
+#endif
+
+    assert(auth_user_request->auth_user != NULL);
+    auth_user = auth_user_request->auth_user;
+
+    /* if the password is not ok, do an identity */
+    if (auth_user->flags.credentials_ok != 1)
+       return;
+
+    assert(auth_user->scheme_data != NULL);
+    basic_auth = auth_user->scheme_data;
+
+    /* are we about to recheck the credentials externally? */
+    if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) {
+       debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n");
+       return;
+    }
+#if 0
+    /*    get the header. */
+    proxy_auth = httpHeaderGetStr(&request->header, type);
+#endif
+
+    /* we have been through the external helper, and the credentials haven't expired */
+    debug(29, 9) ("authenticateBasicAuthenticateuser: user '%s' authenticated\n",
+       basic_auth->username);
+
+    /* Decode now takes care of finding the auth_user struct in the cache */
+#if 0
+    /* see if this is an existing user with a different proxy_auth string */
+    if ((usernamehash = hash_lookup(proxy_auth_username_cache,
+               basic_auth->username))) {
+       while ((usernamehash->auth_user->auth_type != auth_user->auth_type) &&
+           (usernamehash->next) &&
+           !authenticateBasiccmpUsername(usernamehash->auth_user->scheme_data, basic_auth))
+           usernamehash = usernamehash->next;
+       if (usernamehash->auth_user->auth_type == auth_user->auth_type) {
+           /*
+            * add another link from the new proxy_auth to the
+            * auth_user structure and update the information */
+           assert(proxy_auth_hash == NULL);
+           authenticateProxyAuthCacheAddLink(proxy_auth, usernamehash->auth_user);
+           /* maybe the p/w changed. update in the old structure */
+           temp_auth = usernamehash->auth_user->scheme_data;
+           xfree(temp_auth->passwd);
+           temp_auth->passwd = basic_auth->passwd;
+           basic_auth->passwd = NULL;
+           /* and remove the temporary structure */
+           authenticateAuthUserUnlock(auth_user);
+#if 0
+           authenticateFreeProxyAuthUser(auth_user);
+#endif
+           auth_user = usernamehash->auth_user;
+           /* and reference the existing basic data structure */
+           basic_auth = auth_user->scheme_data;
+           /* lock the structure for this request */
+           authenticateAuthUserLock(auth_user);
+       }
+    } else {
+       /* store user in hash's */
+       authenticateUserNameCacheAdd(auth_user);
+       authenticateProxyAuthCacheAddLink(proxy_auth, auth_user);
+    }
+    /* auth_user is now linked, we reset these values */
+#endif
+    /* after external auth occurs anyway */
+    auth_user->expiretime = current_time.tv_sec;
+    auth_user->ip_expiretime = squid_curtime;
+    return;
+}
+
+int
+authenticateBasicDirection(auth_user_request_t * auth_user_request)
+{
+/* null auth_user is checked for by authenticateDirection */
+    auth_user_t *auth_user = auth_user_request->auth_user;
+    basic_data *basic_auth = auth_user->scheme_data;
+    switch (auth_user->flags.credentials_ok) {
+    case 0:                    /* not checked */
+       return -1;
+    case 1:                    /* checked & ok */
+       if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime)
+           return -1;
+       return 0;
+    case 2:                    /* paused while waiting for a username:password check on another request */
+       return -1;
+    case 3:                    /* authentication process failed. */
+       return -2;
+    }
+    return -2;
+}
+
+void
+authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
+{
+    if (basicConfig->authenticate) {
+       debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm);
+       httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm);
+    }
+}
+
+/* free any allocated configuration details */
+void
+authBasicFreeConfig(authScheme * scheme)
+{
+    if (basicConfig == NULL)
+       return;
+    assert(basicConfig == scheme->scheme_data);
+    if (basicConfig->authenticate)
+       wordlistDestroy(&basicConfig->authenticate);
+    if (basicConfig->basicAuthRealm)
+       safe_free(basicConfig->basicAuthRealm);
+    xfree(basicConfig);
+    basicConfig = NULL;
+}
+
+void
+authenticateBasicFreeUser(auth_user_t * auth_user)
+{
+    basic_data *basic_auth = auth_user->scheme_data;
+    debug(29, 5) ("authenticateBasicFreeUser: Clearing Basic scheme data\n");
+    if (basic_auth->username)
+       xfree(basic_auth->username);
+    if (basic_auth->passwd)
+       xfree(basic_auth->passwd);
+    memPoolFree(basic_data_pool, auth_user->scheme_data);
+    auth_user->scheme_data = NULL;
+}
+
+static void
+authenticateBasicHandleReply(void *data, char *reply)
+{
+    authenticateStateData *r = data;
+    auth_user_t *auth_user;
+    basic_data *basic_auth;
+    auth_basic_queue_node *node, *tmpnode;
+    int valid;
+    char *t = NULL;
+    debug(29, 9) ("authenticateBasicHandleReply: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+       if ((t = strchr(reply, ' ')))
+           *t = '\0';
+       if (*reply == '\0')
+           reply = NULL;
+    }
+    assert(r->auth_user_request != NULL);
+    assert(r->auth_user_request->auth_user->auth_type == AUTH_BASIC);
+    auth_user = r->auth_user_request->auth_user;
+    basic_auth = auth_user->scheme_data;
+    if (reply && (strncasecmp(reply, "OK", 2) == 0))
+       auth_user->flags.credentials_ok = 1;
+    else
+       auth_user->flags.credentials_ok = 3;
+    basic_auth->credentials_checkedtime = squid_curtime;
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    if (valid)
+       r->handler(r->data, NULL);
+    node = basic_auth->auth_queue;
+    while (node) {
+       tmpnode = node->next;
+       valid = cbdataValid(node->data);
+       cbdataUnlock(node->data);
+       if (valid)
+           node->handler(node->data, NULL);
+       xfree(node);
+       node = tmpnode;
+    }
+#if 0
+    if (valid)
+       r->handler(r->data, reply);
+#endif
+    authenticateStateFree(r);
+}
+
+static void
+authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+{
+    auth_basic_config *config = scheme->scheme_data;
+    wordlist *list = config->authenticate;
+    storeAppendPrintf(entry, "%s %s", name, "basic");
+    while (list != NULL) {
+       storeAppendPrintf(entry, " %s", list->key);
+       list = list->next;
+    }
+    storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n",
+       name, "basic", config->basicAuthRealm,
+       name, "basic", config->authenticateChildren,
+       name, "basic", config->credentialsTTL);
+
+}
+
+static void
+authBasicParse(authScheme * scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data == NULL) {
+       assert(basicConfig == NULL);
+       /* this is the first param to be found */
+       scheme->scheme_data = xmalloc(sizeof(auth_basic_config));
+       memset(scheme->scheme_data, 0, sizeof(auth_basic_config));
+       basicConfig = scheme->scheme_data;
+       basicConfig->authenticateChildren = 5;
+    }
+    basicConfig = scheme->scheme_data;
+    if (strcasecmp(param_str, "program") == 0) {
+       parse_wordlist(&basicConfig->authenticate);
+       requirePathnameExists("authparam basic program", basicConfig->authenticate->key);
+    } else if (strcasecmp(param_str, "children") == 0) {
+       parse_int(&basicConfig->authenticateChildren);
+    } else if (strcasecmp(param_str, "realm") == 0) {
+       parse_eol(&basicConfig->basicAuthRealm);
+    } else if (strcasecmp(param_str, "credentialsttl") == 0) {
+       parse_time_t(&basicConfig->credentialsTTL);
+    } else {
+       debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str);
+    }
+}
+
+static void
+authenticateBasicStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n");
+    helperStats(sentry, basicauthenticators);
+}
+
+CBDATA_TYPE(authenticateStateData);
+
+/* authenticateBasicUsername: return a pointer to the username in the */
+char *
+authenticateBasicUsername(auth_user_t * auth_user)
+{
+    basic_data *basic_auth = auth_user->scheme_data;
+    if (basic_auth)
+       return basic_auth->username;
+    return NULL;
+}
+
+basic_data *
+authBasicDataNew()
+{
+    basic_data *temp;
+    temp = memPoolAlloc(basic_data_pool);
+    assert(temp != NULL);
+    temp->username = NULL;
+    temp->passwd = NULL;
+    temp->auth_queue = NULL;
+    return temp;
+}
+
+void
+authBasicDataFree(basic_data * basic_auth)
+{
+}
+
+auth_user_t *
+authBasicAuthUserFindUsername(const char *username)
+{
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    debug(29, 9) ("authBasicAuthUserFindUsername: Looking for user '%s'\n", username);
+    if (username && (usernamehash = hash_lookup(proxy_auth_username_cache, username))) {
+       while ((usernamehash->auth_user->auth_type != AUTH_BASIC) &&
+           (usernamehash->next))
+           usernamehash = usernamehash->next;
+       auth_user = NULL;
+       if (usernamehash->auth_user->auth_type == AUTH_BASIC) {
+           auth_user = usernamehash->auth_user;
+       }
+       return auth_user;
+    }
+    return NULL;
+}
+
+
+
+/*
+ * Decode a Basic [Proxy-]Auth string, linking the passed auth_user_request structure 
+ * to any existing user structure or creating one if needed. Note that just returning
+ * will be treated as "cannot decode credentials". Use the message field to return a 
+ * descriptive message to the user.
+ */
+
+static void
+authenticateBasicDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
+{
+    char *sent_auth;
+    char *cleartext;
+    basic_data *basic_auth, local_basic;
+    auth_user_t *auth_user;
+    dlink_node *node;
+
+    /* decode the username */
+    /* trim BASIC from string */
+    while (!xisspace(*proxy_auth))
+       proxy_auth++;
+
+    local_basic.passwd = NULL;
+
+    /* Trim leading whitespace before decoding */
+    while (xisspace(*proxy_auth))
+       proxy_auth++;
+    /* username and password */
+    sent_auth = xstrdup(proxy_auth);
+    /* Trim trailing \n before decoding */
+    strtok(sent_auth, "\n");
+    cleartext = uudecode(sent_auth);
+    xfree(sent_auth);
+    /*
+     * Don't allow NL or CR in the credentials.
+     * Oezguer Kesim <oec@codeblau.de>
+     */
+    strtok(cleartext, "\r\n");
+    debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext);
+    local_basic.username = xstrndup(cleartext, USER_IDENT_SZ);
+    xfree(cleartext);
+    if ((cleartext = strchr(local_basic.username, ':')) != NULL)
+       *(cleartext)++ = '\0';
+    local_basic.passwd = cleartext;
+    if (cleartext == NULL) {
+       debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n",
+           proxy_auth);
+       local_basic.passwd = NULL;
+       auth_user_request->message = xstrdup("no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug");
+    } else if (*cleartext == '\0') {
+       debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password,"
+           "user is '%s'\n", local_basic.username);
+       local_basic.passwd = NULL;
+       auth_user_request->message = xstrdup("Request denied because you provided an empty password. Users MUST have a password.");
+    }
+    /* special case: we have to free the strings for user and password
+     * if we are not returning a filled out structure 
+     */
+    if (local_basic.passwd == NULL) {
+       if (local_basic.username) {
+           /* log the username */
+           debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", local_basic.username);
+           /* new auth_user */
+           auth_user = authenticateAuthUserNew("basic");
+           /* new scheme data */
+           basic_auth = authBasicDataNew();
+           /* save the credentials */
+           basic_auth->username = local_basic.username;
+           /* link the scheme data in */
+           auth_user->scheme_data = basic_auth;
+           /* set the auth_user type */
+           auth_user->auth_type = AUTH_BROKEN;
+           /* link the request to the user */
+           auth_user_request->auth_user = auth_user;
+           /* lock for the auth_user_request link */
+           authenticateAuthUserLock(auth_user);
+           node = dlinkNodeNew();
+           dlinkAdd(auth_user_request, node, &auth_user->requests);
+#if 0
+           xfree(local_basic.username);
+#endif
+       }
+#if 0
+       memPoolFree(basic_data_pool, basic_auth);
+       auth_user->scheme_data = NULL;
+#endif
+       return;
+    } else {
+       local_basic.passwd = xstrndup(cleartext, USER_IDENT_SZ);
+    }
+
+    /* now lookup and see if we have a matching auth_user structure in memory. */
+
+    if ((auth_user = authBasicAuthUserFindUsername(local_basic.username)) == NULL) {
+       /* the user doesn't exist in the username cache yet */
+       debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", local_basic.username);
+       /* new auth_user */
+       auth_user = authenticateAuthUserNew("basic");
+       /* new scheme data */
+       basic_auth = authBasicDataNew();
+       /* save the credentials */
+       basic_auth->username = local_basic.username;
+       basic_auth->passwd = local_basic.passwd;
+       /* link the scheme data in */
+       auth_user->scheme_data = basic_auth;
+       /* set the auth_user type */
+       auth_user->auth_type = AUTH_BASIC;
+       /* current time for timeouts */
+       auth_user->expiretime = current_time.tv_sec;
+       auth_user->ip_expiretime = squid_curtime;
+
+       /* this auth_user struct is the 'lucky one' to get added to the username cache */
+       /* the requests after this link to the auth_user */
+       /* store user in hash */
+       authenticateUserNameCacheAdd(auth_user);
+    } else {
+       debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%d'\n", local_basic.username, auth_user);
+       xfree(local_basic.username);
+       basic_auth = auth_user->scheme_data;
+       if (strcmp(local_basic.passwd, basic_auth->passwd)) {
+           debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n");
+           auth_user->flags.credentials_ok = 0;
+           xfree(basic_auth->passwd);
+           basic_auth->passwd = local_basic.passwd;
+       } else
+           xfree(local_basic.passwd);
+    }
+    /* link the request to the user */
+    auth_user_request->auth_user = auth_user;
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user->requests);
+    return;
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authBasicInit(authScheme * scheme)
+{
+    static int init = 0;
+    if (basicConfig->authenticate) {
+       if (!basic_data_pool)
+           basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data));
+       authbasic_initialised = 1;
+       if (basicauthenticators == NULL)
+           basicauthenticators = helperCreate("basicauthenticator");
+       basicauthenticators->cmdline = basicConfig->authenticate;
+       basicauthenticators->n_to_start = basicConfig->authenticateChildren;
+       basicauthenticators->ipc_type = IPC_TCP_SOCKET;
+       helperOpenServers(basicauthenticators);
+       if (!init) {
+           cachemgrRegister("basicauthenticator",
+               "User Authenticator Stats",
+               authenticateBasicStats, 0, 1);
+           init++;
+       }
+       CBDATA_INIT_TYPE(authenticateStateData);
+    }
+}
+
+/* send the initial data to a basic authenticator module */
+static void
+authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+    authenticateStateData *r = NULL;
+    char buf[8192];
+    basic_data *basic_auth;
+    assert(auth_user_request);
+    assert(handler);
+    assert(auth_user_request->auth_user->auth_type == AUTH_BASIC);
+    assert(auth_user_request->auth_user->scheme_data != NULL);
+    basic_auth = auth_user_request->auth_user->scheme_data;
+    debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username,
+       basic_auth->passwd);
+    if (basicConfig->authenticate == NULL) {
+       handler(data, NULL);
+       return;
+    }
+    /* check to see if the auth_user already has a request outstanding */
+    if (auth_user_request->auth_user->flags.credentials_ok == 2) {
+       /* there is a request with the same credentials already being verified */
+       auth_basic_queue_node *node;
+       node = xmalloc(sizeof(auth_basic_queue_node));
+       assert(node);
+       /* save the details */
+       node->next = basic_auth->auth_queue;
+       basic_auth->auth_queue = node;
+       node->auth_user_request = auth_user_request;
+       node->handler = handler;
+       node->data = data;
+       cbdataLock(data);
+       return;
+    } else {
+       r = CBDATA_ALLOC(authenticateStateData, NULL);
+       r->handler = handler;
+       cbdataLock(data);
+       r->data = data;
+       r->auth_user_request = auth_user_request;
+       /* mark the user as haveing verification in progress */
+       auth_user_request->auth_user->flags.credentials_ok = 2;
+       snprintf(buf, 8192, "%s %s\n", basic_auth->username, basic_auth->passwd);
+       helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r);
+    }
+}
diff --git a/src/auth/basic/auth_basic.h b/src/auth/basic/auth_basic.h
new file mode 100644 (file)
index 0000000..9c49b59
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * auth_basic.h
+ * Internal declarations for the basic auth module
+ */
+
+#ifndef __AUTH_BASIC_H__
+#define __AUTH_BASIC_H__
+
+
+#define DefaultAuthenticateChildrenMax  32     /* 32 processes */
+
+/* Generic */
+typedef struct {
+    void *data;
+    auth_user_request_t *auth_user_request;
+    RH *handler;
+} authenticateStateData;
+
+typedef struct _auth_basic_queue_node auth_basic_queue_node;
+
+/* queue of auth requests waiting for verification to occur */
+struct _auth_basic_queue_node {
+    auth_basic_queue_node *next;
+    auth_user_request_t *auth_user_request;
+    RH *handler;
+    void *data;
+};
+
+struct _basic_data {
+    char *username;
+    char *passwd;
+    time_t credentials_checkedtime;
+    auth_basic_queue_node *auth_queue;
+};
+
+/* configuration runtime data */
+struct _auth_basic_config {
+    int authenticateChildren;
+    char *basicAuthRealm;
+    wordlist *authenticate;
+    time_t credentialsTTL;
+};
+
+typedef struct _auth_basic_config auth_basic_config;
+
+typedef struct _basic_data basic_data;
+
+
+#endif
diff --git a/src/auth/ntlm/Makefile.in b/src/auth/ntlm/Makefile.in
new file mode 100644 (file)
index 0000000..ac491cf
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#  Makefile for the ntlm authentication scheme module for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1 2001/01/07 23:36:48 hno Exp $
+#
+
+AUTH           = ntlm
+
+SUBDIRS                = helpers
+
+top_srcdir     = @top_srcdir@
+VPATH          = @srcdir@
+
+CC             = @CC@
+MAKEDEPEND     = @MAKEDEPEND@
+AR_R           = @AR_R@
+RANLIB         = @RANLIB@
+AC_CFLAGS      = @CFLAGS@
+SHELL          = /bin/sh
+
+INCLUDE                = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+
+OUT            = ../$(AUTH).a
+
+OBJS           = \
+               auth_ntlm.o
+
+
+all install: $(OUT)
+       @for dir in $(SUBDIRS); do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+           fi; \
+       done;
+
+$(OUT): $(OBJS)
+       @rm -f ../stamp
+       $(AR_R) $(OUT) $(OBJS)
+       $(RANLIB) $(OUT)
+
+$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h
+
+.c.o:
+       @rm -f ../stamp
+       $(CC) $(CFLAGS) -c $<
+
+clean: 
+       -rm -rf *.o *pure_* core ../$(AUTH).a
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) clean"; \
+           fi; \
+       done
+
+distclean:     clean
+       -rm -f Makefile
+       -rm -f Makefile.bak
+       -rm -f tags
+       -for dir in *; do \
+           if [ -f $$dir/Makefile ]; then \
+               sh -c "cd $$dir && $(MAKE) distclean"; \
+           fi; \
+       done
+
+tags:
+       ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch]
+
+depend:
+       $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c
diff --git a/src/auth/ntlm/auth_ntlm.cc b/src/auth/ntlm/auth_ntlm.cc
new file mode 100644 (file)
index 0000000..ff439ef
--- /dev/null
@@ -0,0 +1,1015 @@
+
+/*
+ * $Id: auth_ntlm.cc,v 1.1 2001/01/07 23:36:48 hno Exp $
+ *
+ * DEBUG: section 29    NTLM Authenticator
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_ntlm.h"
+
+static void
+authenticateStateFree(authenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* NTLM Scheme */
+static HLPSCB authenticateNTLMHandleReply;
+static HLPSCB authenticateNTLMHandleplaceholder;
+static AUTHSACTIVE authenticateNTLMActive;
+static AUTHSAUTHED authNTLMAuthenticated;
+static AUTHSAUTHUSER authenticateNTLMAuthenticateUser;
+static AUTHSFIXERR authenticateNTLMFixErrorHeader;
+static AUTHSFREE authenticateNTLMFreeUser;
+static AUTHSDIRECTION authenticateNTLMDirection;
+static AUTHSDECODE authenticateDecodeNTLMAuth;
+static AUTHSDUMP authNTLMCfgDump;
+static AUTHSFREECONFIG authNTLMFreeConfig;
+static AUTHSINIT authNTLMInit;
+static AUTHSONCLOSEC authenticateNTLMOnCloseConnection;
+static AUTHSUSERNAME authenticateNTLMUsername;
+static AUTHSREQFREE authNTLMAURequestFree;
+static AUTHSPARSE authNTLMParse;
+static AUTHSSTART authenticateNTLMStart;
+static AUTHSSTATS authenticateNTLMStats;
+static AUTHSSHUTDOWN authNTLMDone;
+
+/* helper callbacks to handle per server state data */
+static HLPSAVAIL authenticateNTLMHelperServerAvailable;
+static HLPSONEQ authenticateNTLMHelperServerOnEmpty;
+
+static statefulhelper *ntlmauthenticators = NULL;
+
+CBDATA_TYPE(authenticateStateData);
+
+static int authntlm_initialised = 0;
+
+MemPool *ntlm_helper_state_pool = NULL;
+MemPool *ntlm_user_pool = NULL;
+MemPool *ntlm_request_pool = NULL;
+static auth_ntlm_config *ntlmConfig = NULL;
+
+static hash_table *proxy_auth_cache = NULL;
+
+/*
+ *
+ * Private Functions
+ *
+ */
+
+void
+authNTLMDone(void)
+{
+//    memPoolDestroy(ufs_state_pool);
+
+    if (ntlmauthenticators)
+       helperStatefulShutdown(ntlmauthenticators);
+    authntlm_initialised = 0;
+    if (!shutting_down)
+       return;
+    helperStatefulFree(ntlmauthenticators);
+    ntlmauthenticators = NULL;
+    memPoolDestroy(ntlm_helper_state_pool);
+    memPoolDestroy(ntlm_request_pool);
+    memPoolDestroy(ntlm_user_pool);
+
+}
+
+/* free any allocated configuration details */
+void
+authNTLMFreeConfig(authScheme * scheme)
+{
+    if (ntlmConfig == NULL)
+       return;
+    assert(ntlmConfig == scheme->scheme_data);
+    if (ntlmConfig->authenticate)
+       wordlistDestroy(&ntlmConfig->authenticate);
+    xfree(ntlmConfig);
+    ntlmConfig = NULL;
+}
+
+static void
+authNTLMCfgDump(StoreEntry * entry, const char *name, authScheme * scheme)
+{
+    auth_ntlm_config *config = scheme->scheme_data;
+    wordlist *list = config->authenticate;
+    storeAppendPrintf(entry, "%s %s", name, "ntlm");
+    while (list != NULL) {
+       storeAppendPrintf(entry, " %s", list->key);
+       list = list->next;
+    }
+    storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n",
+       name, "ntlm", config->authenticateChildren,
+       name, "ntlm", config->challengeuses,
+       name, "ntlm", config->challengelifetime);
+
+}
+
+static void
+authNTLMParse(authScheme * scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data == NULL) {
+       assert(ntlmConfig == NULL);
+       /* this is the first param to be found */
+       scheme->scheme_data = xmalloc(sizeof(auth_ntlm_config));
+       memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config));
+       ntlmConfig = scheme->scheme_data;
+       ntlmConfig->authenticateChildren = 5;
+       ntlmConfig->challengeuses = 0;
+       ntlmConfig->challengelifetime = 60;
+    }
+    ntlmConfig = scheme->scheme_data;
+    if (strcasecmp(param_str, "program") == 0) {
+       parse_wordlist(&ntlmConfig->authenticate);
+       requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key);
+    } else if (strcasecmp(param_str, "children") == 0) {
+       parse_int(&ntlmConfig->authenticateChildren);
+    } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) {
+       parse_int(&ntlmConfig->challengeuses);
+    } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) {
+       parse_time_t(&ntlmConfig->challengelifetime);
+    } else {
+       debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str);
+    }
+}
+
+
+void
+authSchemeSetup_ntlm(authscheme_entry_t * authscheme)
+{
+#if 0
+    static int ntlminit = 0;
+#endif
+    assert(!authntlm_initialised);
+    authscheme->Active = authenticateNTLMActive;
+    authscheme->parse = authNTLMParse;
+    authscheme->dump = authNTLMCfgDump;
+    authscheme->requestFree = authNTLMAURequestFree;
+    authscheme->freeconfig = authNTLMFreeConfig;
+    authscheme->init = authNTLMInit;
+    authscheme->authAuthenticate = authenticateNTLMAuthenticateUser;
+    authscheme->authenticated = authNTLMAuthenticated;
+    authscheme->authFixHeader = authenticateNTLMFixErrorHeader;
+    authscheme->FreeUser = authenticateNTLMFreeUser;
+    authscheme->authStart = authenticateNTLMStart;
+    authscheme->authStats = authenticateNTLMStats;
+    authscheme->authUserUsername = authenticateNTLMUsername;
+    authscheme->getdirection = authenticateNTLMDirection;
+    authscheme->decodeauth = authenticateDecodeNTLMAuth;
+    authscheme->donefunc = authNTLMDone;
+    authscheme->oncloseconnection = authenticateNTLMOnCloseConnection;
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authNTLMInit(authScheme * scheme)
+{
+    static int ntlminit = 0;
+    if (ntlmConfig->authenticate) {
+       if (!ntlm_helper_state_pool)
+           ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t));
+       if (!ntlm_user_pool)
+           ntlm_user_pool = memPoolCreate("NTLM Scheme User Data", sizeof(ntlm_user_t));
+       if (!ntlm_request_pool)
+           ntlm_request_pool = memPoolCreate("NTLM Scheme Request Data", sizeof(ntlm_request_t));
+       authntlm_initialised = 1;
+       if (ntlmauthenticators == NULL)
+           ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
+       if (!proxy_auth_cache)
+           proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+       assert(proxy_auth_cache);
+       ntlmauthenticators->cmdline = ntlmConfig->authenticate;
+       ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren;
+       ntlmauthenticators->ipc_type = IPC_TCP_SOCKET;
+       ntlmauthenticators->datapool = ntlm_helper_state_pool;
+       ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable;
+       ntlmauthenticators->OnEmptyQueue = authenticateNTLMHelperServerOnEmpty;
+       helperStatefulOpenServers(ntlmauthenticators);
+       /* TODO: In here send the initial YR to preinitialise the challenge cache */
+       /* Think about this... currently we ask when the challenge is needed. Better? */
+       if (!ntlminit) {
+           cachemgrRegister("ntlmauthenticator",
+               "User NTLM Authenticator Stats",
+               authenticateNTLMStats, 0, 1);
+           ntlminit++;
+       }
+       CBDATA_INIT_TYPE(authenticateStateData);
+    }
+}
+
+int
+authenticateNTLMActive()
+{
+    if (authntlm_initialised)
+       return 1;
+    else
+       return 0;
+}
+
+/* NTLM Scheme */
+
+int
+authenticateNTLMDirection(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request = auth_user_request->scheme_data;
+/* null auth_user is checked for by authenticateDirection */
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NONE:      /* no progress at all. */
+       debug(28, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev.\n");
+       return -2;
+    case AUTHENTICATE_STATE_NEGOTIATE:         /* send to helper */
+    case AUTHENTICATE_STATE_RESPONSE:  /*send to helper */
+       return -1;
+    case AUTHENTICATE_STATE_CHALLENGE:         /* send to client */
+       return 1;
+    case AUTHENTICATE_STATE_DONE:      /* do nothing.. */
+       return 0;
+    }
+    return -2;
+}
+
+/*
+ * Send the authenticate error header(s). Note: IE has a bug and the NTLM header
+ * must be first. To ensure that, the configure use --enable-auth=ntlm, anything
+ * else.
+ */
+void
+authenticateNTLMFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request)
+{
+    ntlm_request_t *ntlm_request;
+    if (ntlmConfig->authenticate) {
+       /* New request, no user details */
+       if (auth_user_request == NULL) {
+           debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
+           httpHeaderPutStrf(&rep->header, type, "NTLM");
+           /* drop the connection */
+           httpHeaderDelByName(&rep->header, "keep-alive");
+           /* NTLM has problems if the initial connection is not dropped
+            * I haven't checked the RFC compliance of this hack - RBCollins */
+           request->flags.proxy_keepalive = 0;
+       } else {
+           ntlm_request = auth_user_request->scheme_data;
+           switch (ntlm_request->auth_state) {
+           case AUTHENTICATE_STATE_NONE:
+               debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type);
+               httpHeaderPutStrf(&rep->header, type, "NTLM");
+               /* drop the connection */
+               httpHeaderDelByName(&rep->header, "keep-alive");
+               /* NTLM has problems if the initial connection is not dropped
+                * I haven't checked the RFC compliance of this hack - RBCollins */
+               request->flags.proxy_keepalive = 0;
+               break;
+           case AUTHENTICATE_STATE_CHALLENGE:
+               /* we are 'waiting' for a response */
+               /* pass the challenge to the client */
+               debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->authchallenge);
+               httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge);
+               break;
+           default:
+               debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state);
+               fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
+           }
+       }
+    }
+}
+
+void
+authNTLMRequestFree(ntlm_request_t * ntlm_request)
+{
+    if (!ntlm_request)
+       return;
+    if (ntlm_request->ntlmnegotiate)
+       xfree(ntlm_request->ntlmnegotiate);
+    if (ntlm_request->authchallenge)
+       xfree(ntlm_request->authchallenge);
+    if (ntlm_request->ntlmauthenticate)
+       xfree(ntlm_request->ntlmauthenticate);
+    memPoolFree(ntlm_request_pool, ntlm_request);
+}
+
+void
+authNTLMAURequestFree(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request->scheme_data)
+       authNTLMRequestFree((ntlm_request_t *) auth_user_request->scheme_data);
+    auth_user_request->scheme_data = NULL;
+}
+
+void
+authenticateNTLMFreeUser(auth_user_t * auth_user)
+{
+    dlink_node *link, *tmplink;
+    ntlm_user_t *ntlm_user = auth_user->scheme_data;
+    auth_user_hash_pointer *proxy_auth_hash;
+
+    debug(29, 5) ("authenticateNTLMFreeUser: Clearing NTLM scheme data\n");
+    if (ntlm_user->username)
+       xfree(ntlm_user->username);
+    /* were they linked in by one or more proxy-authenticate headers */
+    link = ntlm_user->proxy_auth_list.head;
+    while (link) {
+       debug(29, 9) ("authenticateFreeProxyAuthUser: removing proxy_auth hash entry '%d'\n", link->data);
+       proxy_auth_hash = link->data;
+       tmplink = link;
+       link = link->next;
+       dlinkDelete(tmplink, &ntlm_user->proxy_auth_list);
+       hash_remove_link(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+       /* free the key (usually the proxy_auth header) */
+       xfree(proxy_auth_hash->key);
+       memFree(proxy_auth_hash, MEM_AUTH_USER_HASH);
+    }
+    memPoolFree(ntlm_user_pool, ntlm_user);
+    auth_user->scheme_data = NULL;
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleplaceholder(void *data, void *lastserver, char *reply)
+{
+    authenticateStateData *r = data;
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+    int valid;
+    /* we should only be called for placeholder requests - which have no reply string */
+    assert(reply == NULL);
+    assert(r->auth_user_request);
+    /* standard callback stuff */
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    /* call authenticateNTLMStart to retry this request */
+    debug(29, 9) ("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n");
+    authenticateNTLMStart(r->auth_user_request, r->handler, r->data);
+    authenticateStateFree(r);
+    return result;
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
+{
+#if 0
+    authenticateStatefulStateData *r = data;
+#endif
+    authenticateStateData *r = data;
+    ntlm_helper_state_t *helperstate;
+    int valid;
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+#if 0
+    void *nextserver = NULL;
+#endif
+    char *t = NULL;
+    auth_user_request_t *auth_user_request;
+    auth_user_t *auth_user;
+    ntlm_user_t *ntlm_user;
+    ntlm_request_t *ntlm_request;
+    debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%d' {%s}\n", lastserver, reply ? reply : "<NULL>");
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    if (valid) {
+       if (reply) {
+           /* seperate out the useful data */
+           if (strncasecmp(reply, "TT ", 3) == 0) {
+               reply += 3;
+               /* we have been given a Challenge */
+               /* we should check we weren't given an empty challenge */
+#if 0
+               result = S_HELPER_RESERVE;
+#endif
+               /* copy the challenge to the state data */
+               helperstate = helperStatefulServerGetData(lastserver);
+               if (helperstate == NULL)
+                   fatal("lost NTLm helper state! quitting\n");
+               helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+               helperstate->challengeuses = 0;
+               helperstate->renewed = squid_curtime;
+               /* and we satisfy the request that happended on the refresh boundary */
+               /* note this code is now in two places FIXME */
+               assert(r->auth_user_request != NULL);
+               assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+               auth_user_request = r->auth_user_request;
+               ntlm_request = auth_user_request->scheme_data;
+               assert(ntlm_request != NULL);
+               result = S_HELPER_DEFER;
+#if 0
+               nextserver = lastserver;
+#endif
+               debug(29, 9) ("authenticateNTLMHandleReply: helper '%d'\n", lastserver);
+               assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
+//                auth_user->auth_data.ntlm_auth.auth_state = AUTHENTICATE_STATE_CHALLENGE;
+               ntlm_request->authhelper = lastserver;
+               ntlm_request->authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+           } else if (strncasecmp(reply, "AF ", 3) == 0) {
+               /* we're finished, release the helper */
+               reply += 3;
+               assert(r->auth_user_request != NULL);
+               assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+               auth_user_request = r->auth_user_request;
+               assert(auth_user_request->scheme_data != NULL);
+               ntlm_request = auth_user_request->scheme_data;
+               auth_user = auth_user_request->auth_user;
+               ntlm_user = auth_user_request->auth_user->scheme_data;
+               assert(ntlm_user != NULL);
+               result = S_HELPER_RELEASE;
+               /* we only expect OK when finishing the handshake */
+               assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
+               ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
+               ntlm_request->authhelper = NULL;
+               auth_user->flags.credentials_ok = 1;    /* login ok */
+           } else if (strncasecmp(reply, "NA ", 3) == 0) {
+               /* TODO: only work with auth_user here if it exists */
+               assert(r->auth_user_request != NULL);
+               assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+               auth_user_request = r->auth_user_request;
+               auth_user = auth_user_request->auth_user;
+               assert(auth_user != NULL);
+               ntlm_user = auth_user->scheme_data;
+               ntlm_request = auth_user_request->scheme_data;
+               assert((ntlm_user != NULL) && (ntlm_request != NULL));
+               /* todo: action of Negotiate state on error */
+               result = S_HELPER_RELEASE;      /*some error has occured. no more requests */
+               ntlm_request->authhelper = NULL;
+               auth_user->flags.credentials_ok = 2;    /* Login/Usercode failed */
+               debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM.\n");
+               ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+               if ((t = strchr(reply, ' ')))   /* strip after a space */
+                   *t = '\0';
+           } else if (strncasecmp(reply, "BH ", 3) == 0) {
+               /* TODO kick off a refresh process. This can occur after a YR or after
+                * a KK. If after a YR release the helper and resubmit the request via 
+                * Authenticate NTLM start. 
+                * If after a KK deny the user's request w/ 407 and mark the helper as 
+                * Needing YR. */
+               assert(r->auth_user_request != NULL);
+               assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+               auth_user_request = r->auth_user_request;
+               auth_user = auth_user_request->auth_user;
+               assert(auth_user != NULL);
+               ntlm_user = auth_user->scheme_data;
+               ntlm_request = auth_user_request->scheme_data;
+               assert((ntlm_user != NULL) && (ntlm_request != NULL));
+               result = S_HELPER_RELEASE;      /*some error has occured. no more requests for 
+                                                * this helper */
+               helperstate = helperStatefulServerGetData(ntlm_request->authhelper);
+               ntlm_request->authhelper = NULL;
+               if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) {
+                   /* The helper broke on YR. It automatically
+                    * resets */
+                   auth_user->flags.credentials_ok = 3;        /* cannot process */
+                   debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %d.\n", lastserver);
+                   /* mark it for starving */
+                   helperstate->starve = 1;
+                   /* resubmit the request. This helper is currently busy, so we will get
+                    * a different one. */
+                   authenticateNTLMStart(auth_user_request, r->handler, r->data);
+               } else {
+                   /* the helper broke on a KK */
+                   /* first the standard KK stuff */
+                   auth_user->flags.credentials_ok = 2;        /* Login/Usercode failed */
+                   debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM.\n");
+                   ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+                   if ((t = strchr(reply, ' ')))       /* strip after a space */
+                       *t = '\0';
+                   /* now we mark the helper for resetting. */
+                   helperstate->starve = 1;
+               }
+               ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+           } else {
+               /* TODO: only work with auth_user here if it exists */
+               assert(r->auth_user_request != NULL);
+               assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+               auth_user_request = r->auth_user_request;
+               auth_user = auth_user_request->auth_user;
+               assert(auth_user != NULL);
+               ntlm_user = auth_user->scheme_data;
+               ntlm_request = auth_user_request->scheme_data;
+               assert((ntlm_user != NULL) && (ntlm_request != NULL));
+               debug(29, 1) ("authenticateNTLMHandleReply: Unsupported helper response, '%s'\n", reply);
+               /* restart the authentication process */
+               ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+               auth_user->flags.credentials_ok = 3;    /* cannot process */
+               ntlm_request->authhelper = NULL;
+           }
+       } else {
+           fatal("authenticateNTLMHandleReply: called with no result string\n");
+       }
+       r->handler(r->data, NULL);
+    } else {
+       debug(29, 1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%d'.\n", lastserver);
+       result = S_HELPER_RELEASE;
+    }
+    authenticateStateFree(r);
+    debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
+    return result;
+}
+
+#if 0
+static void
+authenticateNTLMStateFree(authenticateNTLMStateData * r)
+{
+    cbdataFree(r);
+}
+
+#endif
+
+static void
+authenticateNTLMStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
+    helperStatefulStats(sentry, ntlmauthenticators);
+}
+
+/* is a particular challenge still valid ? */
+int
+authenticateNTLMValidChallenge(ntlm_helper_state_t * helperstate)
+{
+    if (helperstate->challenge == NULL)
+       return 0;
+    return 1;
+}
+
+/* does our policy call for changing the challenge now? */
+int
+authenticateNTLMChangeChallenge(ntlm_helper_state_t * helperstate)
+{
+    /* don't check for invalid challenges just for expiry choices */
+    /* this is needed because we have to starve the helper until all old
+     * requests have been satisfied */
+    if (helperstate->challengeuses > ntlmConfig->challengeuses)
+       return 1;
+    if (helperstate->renewed + ntlmConfig->challengelifetime >= squid_curtime)
+       return 1;
+    return 0;
+}
+
+/* send the initial data to a stateful ntlm authenticator module */
+static void
+authenticateNTLMStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+#if 0
+    authenticateStatefulStateData *r = NULL;
+#endif
+    authenticateStateData *r = NULL;
+    helper_stateful_server *server;
+    ntlm_helper_state_t *helperstate;
+    char buf[8192];
+    char *sent_string = NULL;
+    ntlm_user_t *ntlm_user;
+    ntlm_request_t *ntlm_request;
+    auth_user_t *auth_user;
+
+    assert(auth_user_request);
+    auth_user = auth_user_request->auth_user;
+    ntlm_user = auth_user->scheme_data;
+    ntlm_request = auth_user_request->scheme_data;
+    assert(ntlm_user);
+    assert(ntlm_request);
+    assert(handler);
+    assert(data);
+    assert(auth_user->auth_type = AUTH_NTLM);
+    debug(29, 9) ("authenticateNTLMStart: auth state '%d'\n", ntlm_request->auth_state);
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NEGOTIATE:
+       sent_string = xstrdup(ntlm_request->ntlmnegotiate);
+       break;
+    case AUTHENTICATE_STATE_RESPONSE:
+       sent_string = xstrdup(ntlm_request->ntlmauthenticate);
+       assert(ntlm_request->authhelper);
+       debug(29, 9) ("authenticateNTLMStart: Asking NTLMauthenticator '%d'.\n", ntlm_request->authhelper);
+       break;
+    default:
+       fatal("Invalid authenticate state for NTLMStart");
+    }
+
+    while (!xisspace(*sent_string))    /*trim NTLM */
+       sent_string++;
+
+    while (xisspace(*sent_string))     /*trim leading spaces */
+       sent_string++;
+
+    debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state);
+    debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string);
+    if (ntlmConfig->authenticate == NULL) {
+       debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string);
+//      handler(data,0, NULL);
+       handler(data, NULL);
+       return;
+    }
+#ifdef NTLMHELPPROTOCOLV2
+    r = CBDATA_ALLOC(authenticateStateData, NULL);
+    r->handler = handler;
+    cbdataLock(data);
+    r->data = data;
+    r->auth_user_request = auth_user_request;
+    snprintf(buf, 8192, "%s\n", sent_string);
+    helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authhelper);
+    debug(29, 9) ("authenticateNTLMstart: finished\n");
+#else
+    /* this is ugly TODO: move the challenge generation routines to their own function and
+     * tidy the logic up to make use of the efficiency we now have */
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NEGOTIATE:
+       /*  
+        * 1: get a helper server
+        * 2: does it have a challenge?
+        * 3: tell it to get a challenge, or give ntlmauthdone the challenge
+        */
+       server = helperStatefulDefer(ntlmauthenticators);
+       helperstate = server ? helperStatefulServerGetData(server) : NULL;
+       while ((server != NULL) &&
+           authenticateNTLMChangeChallenge(helperstate)) {
+           /* flag this helper for challenge changing */
+           helperstate->starve = 1;
+           /* and release the deferred request */
+           helperStatefulReleaseServer(server);
+           server = helperStatefulDefer(ntlmauthenticators);
+           if (server != NULL)
+               helperstate = helperStatefulServerGetData(server);
+       }
+       if (server == NULL)
+           debug(29, 9) ("unable to get a deferred ntlm helper... all helpers are refreshing challenges. Queuing as a placeholder request.\n");
+
+       ntlm_request->authhelper = server;
+       /* tell the log what helper we have been given */
+       debug(29, 9) ("authenticateNTLMStart: helper '%d' assigned\n", server);
+       /* valid challenge? */
+       if ((server == NULL) || !authenticateNTLMValidChallenge(helperstate)) {
+           r = CBDATA_ALLOC(authenticateStateData, NULL);
+           r->handler = handler;
+           cbdataLock(data);
+           r->data = data;
+           r->auth_user_request = auth_user_request;
+           if (server == NULL) {
+               helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, ntlm_request->authhelper);
+           } else {
+               snprintf(buf, 8192, "YR\n");
+               helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authhelper);
+           }
+       } else {
+           /* we have a valid challenge */
+           /* TODO: turn the below into a function and call from here and handlereply */
+           /* increment the challenge uses */
+           helperstate->challengeuses++;
+           /* assign the challenge */
+           ntlm_request->authchallenge =
+               xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ + 5);
+           handler(data, NULL);
+       }
+
+       break;
+    case AUTHENTICATE_STATE_RESPONSE:
+       r = CBDATA_ALLOC(authenticateStateData, NULL);
+       r->handler = handler;
+       cbdataLock(data);
+       r->data = data;
+       r->auth_user_request = auth_user_request;
+       snprintf(buf, 8192, "KK %s\n", sent_string);
+       helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authhelper);
+       debug(29, 9) ("authenticateNTLMstart: finished\n");
+       break;
+    default:
+       fatal("Invalid authenticate state for NTLMStart");
+    }
+#endif
+}
+
+/* callback used by stateful helper routines */
+int
+authenticateNTLMHelperServerAvailable(void *data)
+{
+    ntlm_helper_state_t *statedata = data;
+    if (statedata != NULL) {
+       if (statedata->starve) {
+           debug(29, 4) ("authenticateNTLMHelperServerAvailable: starving - returning 0\n");
+           return 0;
+       } else {
+           debug(29, 4) ("authenticateNTLMHelperServerAvailable: not starving - returning 1\n");
+           return 1;
+       }
+    }
+    debug(29, 4) ("authenticateNTLMHelperServerAvailable: no state data - returning 0\n");
+    return 0;
+}
+
+void
+authenticateNTLMHelperServerOnEmpty(void *data)
+{
+    ntlm_helper_state_t *statedata = data;
+    if (statedata == NULL)
+       return;
+    if (statedata->starve) {
+       /* we have been starving the helper */
+       debug(29, 9) ("authenticateNTLMHelperServerOnEmpty: resetting challenge details\n");
+       statedata->starve = 0;
+       statedata->challengeuses = 0;
+       statedata->renewed = 0;
+       xfree(statedata->challenge);
+       statedata->challenge = NULL;
+    }
+}
+
+
+/* clear the NTLM helper of being reserved for future requests */
+void
+authenticateNTLMReleasehelper(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request;
+    assert(auth_user_request->auth_user->auth_type == AUTH_NTLM);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_request = auth_user_request->scheme_data;
+    debug(29, 9) ("authenticateNTLMReleasehelper: releasing helper '%d'\n", ntlm_request->authhelper);
+    helperStatefulReleaseServer(ntlm_request->authhelper);
+    ntlm_request->authhelper = NULL;
+}
+
+/* clear any connection related authentication details */
+void
+authenticateNTLMOnCloseConnection(ConnStateData * conn)
+{
+    ntlm_request_t *ntlm_request;
+    assert(conn != NULL);
+    if (conn->auth_user_request != NULL) {
+       assert(conn->auth_user_request->scheme_data != NULL);
+       ntlm_request = conn->auth_user_request->scheme_data;
+       if (ntlm_request->authhelper != NULL)
+           authenticateNTLMReleasehelper(conn->auth_user_request);
+       /* unlock the connection based lock */
+       debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n");
+       authenticateAuthUserRequestUnlock(conn->auth_user_request);
+       conn->auth_user_request = NULL;
+    }
+}
+
+/* authenticateUserUsername: return a pointer to the username in the */
+char *
+authenticateNTLMUsername(auth_user_t * auth_user)
+{
+    ntlm_user_t *ntlm_user = auth_user->scheme_data;
+    if (ntlm_user)
+       return ntlm_user->username;
+    return NULL;
+}
+
+
+/*
+ * Decode an NTLM [Proxy-]Auth string, placing the results in the passed
+ * Auth_user structure.
+ */
+
+void
+authenticateDecodeNTLMAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
+{
+    dlink_node *node;
+    assert(auth_user_request->auth_user == NULL);
+    auth_user_request->auth_user = authenticateAuthUserNew("ntlm");
+    auth_user_request->auth_user->auth_type = AUTH_NTLM;
+    auth_user_request->auth_user->scheme_data = memPoolAlloc(ntlm_user_pool);
+    auth_user_request->scheme_data = memPoolAlloc(ntlm_request_pool);
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user_request->auth_user);
+    node = dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests);
+
+    /* all we have to do is identify that it's NTLM - the helper does the rest */
+    debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n");
+    return;
+}
+
+int
+authenticateNTLMcmpUsername(ntlm_user_t * u1, ntlm_user_t * u2)
+{
+    return strcmp(u1->username, u2->username);
+}
+
+void
+authenticateProxyAuthCacheAddLink(const char *key, auth_user_t * auth_user)
+{
+    auth_user_hash_pointer *proxy_auth_hash;
+    ntlm_user_t *ntlm_user;
+    proxy_auth_hash =
+       memAllocate(MEM_AUTH_USER_HASH);
+    proxy_auth_hash->key = xstrdup(key);
+    proxy_auth_hash->auth_user = auth_user;
+    ntlm_user = auth_user->scheme_data;
+    dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link,
+       &ntlm_user->proxy_auth_list);
+    hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+}
+
+
+int
+authNTLMAuthenticated(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request = auth_user_request->scheme_data;
+    if (ntlm_request->auth_state == AUTHENTICATE_STATE_DONE)
+       return 1;
+    debug(29, 9) ("User not fully authenticated.\n");
+    return 0;
+}
+
+#if 0
+static acl_proxy_auth_user *
+authenticateNTLMAuthenticateUser(void *data, const char *proxy_auth, ConnStateData * conn)
+#else
+static void
+authenticateNTLMAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+#endif
+{
+    const char *proxy_auth;
+    auth_user_hash_pointer *usernamehash, *proxy_auth_hash = NULL;
+    auth_user_t *auth_user;
+    ntlm_request_t *ntlm_request;
+    ntlm_user_t *ntlm_user;
+    LOCAL_ARRAY(char, ntlmhash, NTLM_CHALLENGE_SZ * 2);
+    /* get header */
+    proxy_auth = httpHeaderGetStr(&request->header, type);
+
+    auth_user = auth_user_request->auth_user;
+    assert(auth_user);
+    assert(auth_user->auth_type == AUTH_NTLM);
+    assert(auth_user->scheme_data != NULL);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_user = auth_user->scheme_data;
+    ntlm_request = auth_user_request->scheme_data;
+    switch (ntlm_request->auth_state) {
+    case AUTHENTICATE_STATE_NONE:
+       /* we've recieved a negotiate request. pass to a helper */
+       debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm none. %s\n",
+           proxy_auth);
+       ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE;
+       ntlm_request->ntlmnegotiate = xstrndup(proxy_auth, NTLM_CHALLENGE_SZ + 5);
+       conn->auth_type = AUTH_NTLM;
+       conn->auth_user_request = auth_user_request;
+       /* and lock for the connection duration */
+       debug(29, 9) ("authenticateNTLMAuthenticateUser: Locking auth_user from the connection.\n");
+       authenticateAuthUserRequestLock(auth_user_request);
+       return;
+       break;
+    case AUTHENTICATE_STATE_NEGOTIATE:
+       ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE;
+       return;
+       break;
+    case AUTHENTICATE_STATE_CHALLENGE:
+       /* we should have recieved a NTLM challenge. pass it to the same 
+        * helper process */
+       debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state challenge with header %s.\n", proxy_auth);
+       /* do a cache lookup here. If it matches it's a successful ntlm 
+        * challenge - release the helper and use the existing auth_user 
+        * details. */
+       if (strncmp("NTLM ", proxy_auth, 5) == 0) {
+           ntlm_request->ntlmauthenticate = xstrdup(proxy_auth);
+       } else {
+           fatal("Incorrect scheme in auth header\n");
+           /* TODO: more fault tolerance.. reset the auth scheme here */
+       }
+       /* cache entries have authenticateauthheaderchallengestring */
+       snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
+           ntlm_request->ntlmauthenticate,
+           ntlm_request->authchallenge);
+       /* see if we already know this user's authenticate */
+       debug(29, 9) ("aclMatchProxyAuth: cache lookup with key '%s'\n", ntlmhash);
+       assert(proxy_auth_cache != NULL);
+       proxy_auth_hash = hash_lookup(proxy_auth_cache, ntlmhash);
+       if (!proxy_auth_hash) { /* not in the hash table */
+           debug(29, 4) ("authenticateNTLMAuthenticateUser: proxy-auth cache miss.\n");
+           ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE;
+           /* verify with the ntlm helper */
+       } else {
+           debug(29, 4) ("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n");
+           /* throw away the temporary entry */
+           authenticateNTLMReleasehelper(auth_user_request);
+           authenticateAuthUserMerge(auth_user, proxy_auth_hash->auth_user);
+           auth_user = proxy_auth_hash->auth_user;
+           auth_user_request->auth_user = auth_user;
+           ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
+           /* we found one */
+           debug(29, 9) ("found matching cache entry\n");
+           assert(auth_user->auth_type == AUTH_NTLM);
+           /* get the existing entries details */
+           ntlm_user = auth_user->scheme_data;
+           debug(29, 9) ("Username to be used is %s\n",
+               ntlm_user->username);
+           auth_user->flags.credentials_ok = 1;        /* authenticated ok */
+           /* on ntlm auth we do not unlock the auth_user until the
+            * connection is dropped. Thank MS for this quirk */
+           auth_user->expiretime = current_time.tv_sec;
+           auth_user->ip_expiretime = squid_curtime;
+       }
+       return;
+       break;
+    case AUTHENTICATE_STATE_RESPONSE:
+       /* auth-challenge pair cache miss. We've just got the response */
+       /*add to cache and let them through */
+       ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
+       /* this connection is authenticated */
+       debug(29, 4) ("authenticated\nch    %s\nauth     %s\nauthuser %s\n",
+           ntlm_request->authchallenge,
+           ntlm_request->ntlmauthenticate,
+           ntlm_user->username);
+       /* cache entries have authenticateauthheaderchallengestring */
+       snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s",
+           ntlm_request->ntlmauthenticate,
+           ntlm_request->authchallenge);
+       /* see if this is an existing user with a different proxy_auth 
+        * string */
+       if ((usernamehash = hash_lookup(proxy_auth_username_cache,
+                   ntlm_user->username))) {
+           while ((usernamehash->auth_user->auth_type !=
+                   auth_user->auth_type) && (usernamehash->next) &&
+               !authenticateNTLMcmpUsername(usernamehash->auth_user->scheme_data, ntlm_user))
+               usernamehash = usernamehash->next;
+           if (usernamehash->auth_user->auth_type == auth_user->auth_type) {
+               /*
+                * add another link from the new proxy_auth to the
+                * auth_user structure and update the information */
+               assert(proxy_auth_hash == NULL);
+               authenticateProxyAuthCacheAddLink(ntlmhash, usernamehash->auth_user);
+               /* we can't seamlessly recheck the username due to the 
+                * challenge nature of the protocol. Just free the 
+                * temporary auth_user */
+               authenticateAuthUserMerge(auth_user, usernamehash->auth_user);
+               auth_user = usernamehash->auth_user;
+               auth_user_request->auth_user = auth_user;
+#if 0
+               conn->auth_user = auth_user;
+#endif
+           }
+       } else {
+           /* store user in hash's */
+           authenticateUserNameCacheAdd(auth_user);
+           authenticateProxyAuthCacheAddLink(ntlmhash, auth_user);
+       }
+       /* set these to now because this is either a new login from an 
+        * existing user or a new user */
+       auth_user->expiretime = current_time.tv_sec;
+       auth_user->ip_expiretime = squid_curtime;
+       auth_user->flags.credentials_ok = 1;    /*authenticated ok */
+       return;
+       break;
+    case AUTHENTICATE_STATE_DONE:
+       fatal("authenticateNTLMAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n");
+#if 0                          /* done in acl.c */
+    case AUTHENTICATE_STATE_DONE:
+       debug(28, 5) ("aclMatchProxyAuth: connection in state Done. using connection credentials for the request. \n");
+       /* is it working right? */
+       assert(checklist->auth_user == NULL);
+       assert(checklist->conn->auth_user != NULL);
+       /* we have a valid username. */
+       auth_user = checklist->conn->auth_user;
+       /* store the username in the request for logging */
+       xstrncpy(checklist->request->authuser,
+           auth_user->auth_data.ntlm_auth.username,
+           USER_IDENT_SZ);
+       if (auth_user->expiretime + Config.authenticateTTL > current_time.tv_sec
+           ) {
+           auth_user->expiretime = current_time.tv_sec;
+       } else {
+           //user passed externa; authentication in every case to get here. f.
+           Let it through
+       }                       /* we don't unlock the auth_user until the connection is dropped. Thank
+                                * MS for this quirk. */ if (authenticateCheckAuthUserIP(checklist->src_addr, auth_user)) {
+           /* Once the match is completed we have finished with the
+            * auth_user structure */
+           /* check to see if we have matched the user-acl before */
+           return aclCacheMatchAcl(&auth_user->proxy_match_cache, acltype,
+               data, auth_user->auth_data.ntlm_auth.username);
+       } else {
+           return 0;
+       }
+       break;
+#endif
+    }
+
+    return;
+}
diff --git a/src/auth/ntlm/auth_ntlm.h b/src/auth/ntlm/auth_ntlm.h
new file mode 100644 (file)
index 0000000..354edad
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * auth_ntlm.h
+ * Internal declarations for the ntlm auth module
+ */
+
+#ifndef __AUTH_NTLM_H__
+#define __AUTH_NTLM_H__
+
+#define DefaultAuthenticateChildrenMax  32     /* 32 processes */
+
+/* Generic */
+typedef struct {
+    void *data;
+    auth_user_request_t *auth_user_request;
+    RH *handler;
+} authenticateStateData;
+
+struct _ntlm_user {
+    /* what username did this connection get? */
+    char *username;
+    dlink_list proxy_auth_list;
+};
+
+struct _ntlm_request {
+    /* what negotiate string did the client use? */
+    char *ntlmnegotiate;
+    /* what challenge did we give the client? */
+    char *authchallenge;
+    /* what authenticate string did we get? */
+    char *ntlmauthenticate;
+    /*we need to store the NTLM helper between requests */
+    helper_stateful_server *authhelper;
+    /* how far through the authentication process are we? */
+    auth_state_t auth_state;
+};
+
+struct _ntlm_helper_state_t {
+    char *challenge;           /* the challenge to use with this helper */
+    int starve;                        /* 0= normal operation. 1=don't hand out any more challenges */
+    int challengeuses;         /* the number of times this challenge has been issued */
+    time_t renewed;
+};
+
+/* configuration runtime data */
+struct _auth_ntlm_config {
+    int authenticateChildren;
+    wordlist *authenticate;
+    int challengeuses;
+    time_t challengelifetime;
+#if 0
+    char *authenticate_ntlm_default_domain;
+#endif
+};
+
+typedef struct _ntlm_user ntlm_user_t;
+typedef struct _ntlm_request ntlm_request_t;
+typedef struct _ntlm_helper_state_t ntlm_helper_state_t;
+typedef struct _auth_ntlm_config auth_ntlm_config;
+
+extern MemPool *ntlm_helper_state_pool;
+extern MemPool *ntlm_user_pool;
+extern MemPool *ntlm_request_pool;
+
+#endif
diff --git a/src/auth_modules.sh b/src/auth_modules.sh
new file mode 100644 (file)
index 0000000..956e7be
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+echo "/* automatically generated by $0 $*"
+echo " * do not edit"
+echo " */"
+echo "#include \"squid.h\""
+echo ""
+for module in "$@"; do
+   echo "extern AUTHSSETUP authSchemeSetup_${module};"
+done
+echo "void authSchemeSetup(void)"
+echo "{"
+for module in "$@"; do
+   echo "      authSchemeAdd(\"$module\", authSchemeSetup_${module});"
+done
+echo "}"
index ce67ad31114e739e98e0a604dbd50b1b8f2f9a89..d03079626a6c09a0601a6478c2cd1919dfffe132 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: authenticate.cc,v 1.14 2001/01/05 09:51:36 adrian Exp $
+ * $Id: authenticate.cc,v 1.15 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR: Duane Wessels
  *
  */
 
-#include "squid.h"
+/* The functions in this file handle authentication.
+ * They DO NOT perform access control or auditing.
+ * See acl.c for access control and client_side.c for auditing */
 
-typedef struct {
-    void *data;
-    acl_proxy_auth_user *auth_user;
-    RH *handler;
-} authenticateStateData;
 
-static HLPCB authenticateHandleReply;
-static void authenticateStateFree(authenticateStateData * r);
-static helper *authenticators = NULL;
+#include "squid.h"
 
 static void
-authenticateHandleReply(void *data, char *reply)
+     authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request);
+
+/*
+ *
+ * Private Data
+ *
+ */
+
+MemPool *auth_user_request_pool = NULL;
+
+/* Generic Functions */
+
+
+int
+authenticateAuthSchemeConfigured(const char *proxy_auth)
 {
-    authenticateStateData *r = data;
-    int valid;
-    char *t = NULL;
-    debug(29, 5) ("authenticateHandleReply: {%s}\n", reply ? reply : "<NULL>");
-    if (reply) {
-       if ((t = strchr(reply, ' ')))
-           *t = '\0';
-       if (*reply == '\0')
-           reply = NULL;
+    authScheme *scheme;
+    int i;
+    for (i = 0; i < Config.authConfig.n_configured; i++) {
+       scheme = Config.authConfig.schemes + i;
+       if (strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0)
+           return 1;
     }
-    valid = cbdataValid(r->data);
-    cbdataUnlock(r->data);
-    if (valid)
-       r->handler(r->data, reply);
-    authenticateStateFree(r);
+    return 0;
 }
 
-static void
-authenticateStateFree(authenticateStateData * r)
+int
+authenticateAuthSchemeId(const char *typestr)
 {
-    cbdataFree(r);
+    int i = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+       if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) {
+           return i;
+       }
+    }
+    return -1;
 }
 
-static void
-authenticateStats(StoreEntry * sentry)
+void
+authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request)
 {
-    storeAppendPrintf(sentry, "Authenticator Statistics:\n");
-    helperStats(sentry, authenticators);
+    int i = 0;
+    assert(proxy_auth != NULL);
+    assert(auth_user_request != NULL); /* we need this created for us. */
+    debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth);
+    if (authenticateAuthSchemeConfigured(proxy_auth)) {
+       /* we're configured to use this scheme - but is it active ? */
+       if ((i = authenticateAuthSchemeId(proxy_auth)) != -1) {
+           authscheme_list[i].decodeauth(auth_user_request, proxy_auth);
+           auth_user_request->auth_user->auth_module = i + 1;
+           return;
+       }
+    }
+    debug(29, 1)
+       ("authenticateDecodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n",
+       proxy_auth);
+    return;
 }
 
-CBDATA_TYPE(authenticateStateData);
-
-/**** PUBLIC FUNCTIONS ****/
+/* clear any connection related authentication details */
+void
+authenticateOnCloseConnection(ConnStateData * conn)
+{
+    auth_user_request_t *auth_user_request;
+    assert(conn != NULL);
+    if (conn->auth_user_request != NULL) {
+       auth_user_request = conn->auth_user_request;
+       if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) {
+           authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn);
+       }
+    }
+}
 
+/**** PUBLIC FUNCTIONS (ALL GENERIC!)  ****/
 
+/* send the initial data to an authenticator module */
 void
-authenticateStart(acl_proxy_auth_user * auth_user, RH * handler, void *data)
+authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
 {
-    authenticateStateData *r = NULL;
-    char buf[8192];
-    assert(auth_user);
+    assert(auth_user_request);
     assert(handler);
-    debug(29, 5) ("authenticateStart: '%s:%s'\n", hashKeyStr(&auth_user->hash),
-       auth_user->passwd);
-    if (Config.Program.authenticate == NULL) {
+    debug(29, 9) ("authenticateStart: auth_user_request '%d'\n", auth_user_request);
+    if (auth_user_request->auth_user->auth_module > 0)
+       authscheme_list[auth_user_request->auth_user->auth_module - 1].authStart(auth_user_request, handler, data);
+    else
        handler(data, NULL);
-       return;
+}
+
+/*
+ * Check a auth_user pointer for validity. Does not check passwords, just data
+ * sensability. Broken or Unknown auth_types are not valid for use...
+ */
+
+int
+authenticateValidateUser(auth_user_request_t * auth_user_request)
+{
+    debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%d'.\n", auth_user_request);
+    if (auth_user_request == NULL) {
+       debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n");
+       return 0;
     }
-    r = CBDATA_ALLOC(authenticateStateData, NULL);
-    r->handler = handler;
-    cbdataLock(data);
-    r->data = data;
-    r->auth_user = auth_user;
-    snprintf(buf, 8192, "%s %s\n", hashKeyStr(&r->auth_user->hash),
-       r->auth_user->passwd);
-    helperSubmit(authenticators, buf, authenticateHandleReply, r);
+    if (auth_user_request->auth_user == NULL) {
+       debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n");
+       return 0;
+    }
+    if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) {
+       debug(29, 4) ("authenticateValidateUser: Auth_user '%d' uses unknown scheme.\n", auth_user_request->auth_user);
+       return 0;
+    }
+    if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) {
+       debug(29, 4) ("authenticateValidateUser: Auth_user '%d' is broken for it's scheme.\n", auth_user_request->auth_user);
+       return 0;
+    }
+    /* any other sanity checks that we need in the future */
+
+    /* Thus should a module call to something like authValidate */
+
+    /* finally return ok */
+    debug(29, 4) ("authenticateValidateUser: Validated Auth_user request '%d'.\n", auth_user_request);
+    return 1;
+
+}
+
+auth_user_t *
+authenticateAuthUserNew(const char *scheme)
+{
+    auth_user_t *temp_auth;
+    temp_auth = memAllocate(MEM_AUTH_USER_T);
+    assert(temp_auth != NULL);
+    temp_auth->auth_type = AUTH_UNKNOWN;
+    temp_auth->references = 0;
+    temp_auth->auth_module = authenticateAuthSchemeId(scheme) + 1;
+    return temp_auth;
+}
+
+auth_user_request_t *
+authenticateAuthUserRequestNew()
+{
+    auth_user_request_t *temp_request;
+    if (!auth_user_request_pool)
+       auth_user_request_pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t));
+    temp_request = memPoolAlloc(auth_user_request_pool);
+    assert(temp_request != NULL);
+    temp_request->auth_user = NULL;
+    temp_request->message = NULL;
+    temp_request->scheme_data = NULL;
+    temp_request->references = 0;
+    return temp_request;
 }
 
 void
-authenticateInit(void)
+authenticateAuthUserRequestFree(auth_user_request_t * auth_user_request)
 {
-    static int init = 0;
-    if (!Config.Program.authenticate)
+    dlink_node *link;
+    debug(29, 5) ("authenticateAuthUserRequestFree: freeing request %d\n", auth_user_request);
+    if (!auth_user_request)
        return;
-    if (authenticators == NULL)
-       authenticators = helperCreate("authenticator");
-    authenticators->cmdline = Config.Program.authenticate;
-    authenticators->n_to_start = Config.authenticateChildren;
-    authenticators->ipc_type = IPC_TCP_SOCKET;
-    helperOpenServers(authenticators);
-    if (!init) {
-       cachemgrRegister("authenticator",
-           "User Authenticator Stats",
-           authenticateStats, 0, 1);
-       init++;
+    assert(auth_user_request->references == 0);
+    if (auth_user_request->auth_user) {
+       if (auth_user_request->scheme_data != NULL) {
+           /* we MUST know the module */
+           assert((auth_user_request->auth_user->auth_module > 0));
+           /* and the module MUST support requestFree if it has created scheme data */
+           assert(authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree != NULL);
+           authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree(auth_user_request);
+       }
+       /* unlink from the auth_user struct */
+       link = auth_user_request->auth_user->requests.head;
+       while (link && (link->data != auth_user_request))
+           link = link->next;
+       assert(link != NULL);
+       dlinkDelete(link, &auth_user_request->auth_user->requests);
+       dlinkNodeDelete(link);
+
+       /* unlock the request structure's lock */
+       authenticateAuthUserUnlock(auth_user_request->auth_user);
+       auth_user_request->auth_user = NULL;
+    } else
+       assert(auth_user_request->scheme_data == NULL);
+    if (auth_user_request->message)
+       xfree(auth_user_request->message);
+}
+
+char *
+authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request)
+       return auth_user_request->message;
+    return NULL;
+}
+
+void
+authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
+{
+    if (auth_user_request->auth_user)
+       if (!auth_user_request->auth_user->ipaddr.s_addr)
+           auth_user_request->auth_user->ipaddr = ipaddr;
+}
+
+/* Get Auth User: Return a filled out auth_user structure for the given
+ * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
+ * Unauthenticated structure. The structure is given an inital lock here.
+ */
+auth_user_request_t *
+authenticateGetAuthUser(const char *proxy_auth)
+{
+    auth_user_request_t *auth_user_request = authenticateAuthUserRequestNew();
+    /* and lock for the callers instance */
+    authenticateAuthUserRequestLock(auth_user_request);
+    authenticateDecodeAuth(proxy_auth, auth_user_request);
+    return auth_user_request;
+}
+
+/*
+ * authenticateUserAuthenticated: is this auth_user structure logged in ?
+ */
+int
+authenticateUserAuthenticated(auth_user_request_t * auth_user_request)
+{
+    assert(authenticateValidateUser(auth_user_request));
+    if (auth_user_request->auth_user->auth_module > 0)
+       return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request);
+    else
+       return 0;
+}
+
+/*
+ * authenticateAuthenticateUser: log this user request in.
+ * Cache hits may change the auth_user pointer in the structure if needed.
+ * This is basically a handle approach.
+ */
+void
+authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
+{
+    assert(auth_user_request != NULL);
+    if (auth_user_request->auth_user->auth_module > 0)
+       authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type);
+}
+
+/* authenticateUserUsername: return a pointer to the username in the */
+char *
+authenticateUserUsername(auth_user_t * auth_user)
+{
+    if (!auth_user)
+       return NULL;
+    if (auth_user->auth_module > 0)
+       return authscheme_list[auth_user->auth_module - 1].authUserUsername(auth_user);
+    return NULL;
+}
+
+/* authenticateUserRequestUsername: return a pointer to the username in the */
+char *
+authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
+{
+    assert(auth_user_request != NULL);
+    return authenticateUserUsername(auth_user_request->auth_user);
+}
+
+/* returns
+ * 0: no output needed
+ * 1: send to client
+ * -1: send to helper
+ * -2: authenticate broken in some fashion
+ */
+int
+authenticateDirection(auth_user_request_t * auth_user_request)
+{
+    if (!auth_user_request)
+       return -2;
+    if (authenticateUserAuthenticated(auth_user_request))
+       return 0;
+    if (auth_user_request->auth_user->auth_module > 0)
+       return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request);
+    return -2;
+}
+
+int
+authenticateActiveSchemeCount()
+{
+    int i = 0, rv = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
+       if (authscheme_list[i].Active())
+           rv++;
+    debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv);
+    return rv;
+}
+
+int
+authenticateSchemeCount()
+{
+    int i = 0, rv = 0;
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
+       rv++;
+    debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv);
+    return rv;
+}
+
+void
+authenticateSchemeInit(void)
+{
+    authSchemeSetup();
+}
+
+void
+authenticateInit(authConfig * config)
+{
+    int i;
+    authScheme *scheme;
+    for (i = 0; i < config->n_configured; i++) {
+       if (authscheme_list[i].init) {
+           scheme = config->schemes + i;
+           authscheme_list[i].init(scheme);
+       }
     }
-    CBDATA_INIT_TYPE(authenticateStateData);
+    if (!proxy_auth_username_cache)
+       authenticateInitUserCache();
 }
 
 void
 authenticateShutdown(void)
 {
-    if (!authenticators)
-       return;
-    helperShutdown(authenticators);
-    if (!shutting_down)
-       return;
-    helperFree(authenticators);
-    authenticators = NULL;
+    int i;
+    debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n");
+    /* find the currently known authscheme types */
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+       if (authscheme_list[i].donefunc != NULL)
+           authscheme_list[i].donefunc();
+       else
+           debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr);
+       authscheme_list[i].typestr = NULL;
+    }
+}
+
+void
+authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
+/* send the auth types we are configured to support (and have compiled in!) */
+{
+/*    auth_type_t auth_type=err->auth_type;
+ * auth_state_t auth_state=err->auth_state;
+ * char *authchallenge=err->authchallenge;
+ * auth_user_request_t *auth_user_request=err->auth_user_request;
+ */
+    int type = 0;
+    switch (rep->sline.status) {
+    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+       /* Proxy authorisation needed */
+       type = HDR_PROXY_AUTHENTICATE;
+       break;
+    case HTTP_UNAUTHORIZED:
+       /* WWW Authorisation needed */
+       type = HDR_WWW_AUTHENTICATE;
+       break;
+    default:
+       /* Keep GCC happy */
+       /* some other HTTP status */
+       break;
+    }
+    debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%d\n", type, auth_user_request);
+    if ((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+       || (rep->sline.status == HTTP_UNAUTHORIZED))
+       /* this is a authenticate-needed response */
+    {
+       if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0))
+           authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request);
+       else {
+           int i;
+           authScheme *scheme;
+           /* call each configured authscheme */
+           for (i = 0; i < Config.authConfig.n_configured; i++) {
+               scheme = Config.authConfig.schemes + i;
+               if (authscheme_list[scheme->Id].Active())
+                   authscheme_list[scheme->Id].authFixHeader(auth_user_request, rep, type,
+                       request);
+               else
+                   debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr);
+           }
+       }
+    }
+    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
+       && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader))
+       authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated);
+}
+
+/* call the active auth module and allow it to add a trailer to the request */
+void
+authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
+{
+    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
+       && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer))
+       authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated);
+}
+
+void
+authenticateAuthUserLock(auth_user_t * auth_user)
+{
+    debug(29, 9) ("authenticateAuthUserLock auth_user '%d'.\n", auth_user);
+    assert(auth_user != NULL);
+    auth_user->references++;
+    debug(29, 9) ("authenticateAuthUserLock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
+}
+
+void
+authenticateAuthUserUnlock(auth_user_t * auth_user)
+{
+    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d'.\n", auth_user);
+    assert(auth_user != NULL);
+    if (auth_user->references > 0) {
+       auth_user->references--;
+    } else {
+       debug(29, 1) ("Attempt to lower Auth User %d refcount below 0!\n", auth_user);
+    }
+    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
+    if (auth_user->references == 0)
+       authenticateFreeProxyAuthUser(auth_user);
+}
+
+void
+authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
+{
+    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d'.\n", auth_user_request);
+    assert(auth_user_request != NULL);
+    auth_user_request->references++;
+    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
+}
+
+void
+authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
+{
+    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user request '%d'.\n", auth_user_request);
+    assert(auth_user_request != NULL);
+    if (auth_user_request->references > 0) {
+       auth_user_request->references--;
+    } else {
+       debug(29, 1) ("Attempt to lower Auth User request %d refcount below 0!\n", auth_user_request);
+    }
+    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user_request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
+    if (auth_user_request->references == 0) {
+       /* not locked anymore */
+       authenticateAuthUserRequestFree(auth_user_request);
+    }
+}
+
+int
+authenticateAuthUserInuse(auth_user_t * auth_user)
+/* returns 0 for not in use */
+{
+    assert(auth_user != NULL);
+    return auth_user->references;
+}
+
+/* Combine two user structs. ONLY to be called from within a scheme module.
+ * The scheme module is responsible for ensuring that the two users _can_ be merged 
+ * without invalidating all the request scheme data. 
+ * the scheme is also responsible for merging any user related scheme data itself. */
+void
+authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
+{
+    dlink_node *link, *tmplink;
+    auth_user_request_t *auth_user_request;
+/* XXX combine two authuser structs. Incomplete: it should merge in hash references 
+ * too and ask the module to merge in scheme data */
+    debug(29, 5) ("authenticateAuthUserMerge auth_user '%d' into auth_user '%d'.\n", from, to);
+    link = from->requests.head;
+    while (link) {
+       auth_user_request = link->data;
+       tmplink = link;
+       link = link->next;
+       dlinkDelete(tmplink, &from->requests);
+       dlinkAddTail(auth_user_request, tmplink, &to->requests);
+       auth_user_request->auth_user = to;
+    }
+    to->references += from->references;
+    from->references = 0;
+    authenticateFreeProxyAuthUser(from);
+}
+
+void
+authenticateFreeProxyAuthUser(void *data)
+{
+    auth_user_t *u = data;
+    auth_user_request_t *auth_user_request;
+#if 0
+    auth_user_hash_pointer *proxy_auth_hash;
+#endif
+    dlink_node *link, *tmplink;
+    assert(data != NULL);
+    debug(29, 5) ("authenticateFreeProxyAuthUser: Freeing auth_user '%d' with refcount '%d'.\n", u, u->references);
+    assert(u->references == 0);
+    /* were they linked in by username ? */
+    if (u->usernamehash) {
+       assert(u->usernamehash->auth_user == u);
+       debug(29, 5) ("authenticateFreeProxyAuthUser: removing usernamehash entry '%d'\n", u->usernamehash);
+       hash_remove_link(proxy_auth_username_cache,
+           (hash_link *) u->usernamehash);
+       /* don't free the key as we use the same user string as the auth_user 
+        * structure */
+       memFree(u->usernamehash, MEM_AUTH_USER_HASH);
+    }
+    /* remove any outstanding requests */
+    link = u->requests.head;
+    while (link) {
+       debug(29, 5) ("authenticateFreeProxyAuthUser: removing request entry '%d'\n", link->data);
+       auth_user_request = link->data;
+       tmplink = link;
+       link = link->next;
+       dlinkDelete(tmplink, &u->requests);
+       dlinkNodeDelete(tmplink);
+       authenticateAuthUserRequestFree(auth_user_request);
+    }
+    /* free cached acl results */
+    aclCacheMatchFlush(&u->proxy_match_cache);
+    if (u->scheme_data && u->auth_module > 0)
+       authscheme_list[u->auth_module - 1].FreeUser(u);
+    /* prevent accidental reuse */
+    u->auth_type = AUTH_UNKNOWN;
+    memFree(u, MEM_AUTH_USER_T);
+}
+
+void
+authenticateInitUserCache()
+{
+    if (!proxy_auth_username_cache) {
+       /* First time around, 7921 should be big enough */
+       proxy_auth_username_cache =
+           hash_create((HASHCMP *) strcmp, 7921, hash_string);
+       assert(proxy_auth_username_cache);
+       eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
+    }
+}
+
+void
+authenticateProxyUserCacheCleanup(void *datanotused)
+{
+    /*
+     * We walk the hash by username as that is the unique key we use.
+     * For big hashs we could consider stepping through the cache, 100/200
+     * entries at a time. Lets see how it flys first.
+     */
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    char *username = NULL;
+    debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n");
+    debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %d\n", current_time.tv_sec);
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
+       auth_user = usernamehash->auth_user;
+       username = authenticateUserUsername(auth_user);
+
+       /* if we need to have inpedendent expiry clauses, insert a module call
+        * here */
+       debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %d\n\treferences: %d\n", auth_user->auth_type, username, auth_user->expiretime + Config.authenticateTTL, auth_user->references);
+       if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
+           debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username);
+           /* the minus 1 accounts for the cache lock */
+           if ((authenticateAuthUserInuse(auth_user) - 1))
+               debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
+           else
+               authenticateAuthUserUnlock(auth_user);
+       }
+    }
+    debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n");
+    eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
+}
+
+/*
+ * authenticateUserCacheRestart() cleans all config-dependent data from the 
+ * auth_user cache. It DOES NOT Flush the user cache.
+ */
+
+void
+authenticateUserCacheRestart()
+{
+    auth_user_hash_pointer *usernamehash;
+    auth_user_t *auth_user;
+    char *username = NULL;
+    debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
+       auth_user = usernamehash->auth_user;
+       username = authenticateUserUsername(auth_user);
+       debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username);
+       aclCacheMatchFlush(&auth_user->proxy_match_cache);
+    }
+
+}
+
+/*
+ * called to add another auth scheme module
+ */
+void
+authSchemeAdd(char *type, AUTHSSETUP * setup)
+{
+    int i;
+    /* find the number of currently known authscheme types */
+    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
+       assert(strcmp(authscheme_list[i].typestr, type) != 0);
+    }
+    /* add the new type */
+    authscheme_list = xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t));
+    memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t));
+    authscheme_list[i].typestr = type;
+    /* Call the scheme module to set up capabilities and initialize any global data */
+    setup(&authscheme_list[i]);
+}
+
+
+
+/* UserNameCacheAdd: add a auth_user structure to the username cache */
+void
+authenticateUserNameCacheAdd(auth_user_t * auth_user)
+{
+    auth_user_hash_pointer *usernamehash;
+    usernamehash = memAllocate(MEM_AUTH_USER_HASH);
+    usernamehash->key = authenticateUserUsername(auth_user);
+    usernamehash->auth_user = auth_user;
+    hash_join(proxy_auth_username_cache, (hash_link *) usernamehash);
+    auth_user->usernamehash = usernamehash;
+    /* lock for presence in the cache */
+    authenticateAuthUserLock(auth_user);
+}
+
+
+
+/*
+ * check the user for ip changes timeouts
+ * 0 = failed check
+ * 1 = ip requirements are ok.
+ */
+/* TODO:
+ * ip_expire data should be in a struct of it's own - for code reuse */
+int
+authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user_request)
+{
+    char *username = authenticateUserRequestUsername(auth_user_request);
+    if (request_src_addr.s_addr == auth_user_request->auth_user->ipaddr.s_addr || auth_user_request->auth_user->ip_expiretime + Config.authenticateIpTTL <= squid_curtime) {
+       /* user has not moved ip or had the ip timeout expire */
+       if ((auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) ||
+           (auth_user_request->auth_user->auth_type == AUTH_BROKEN)) {
+           debug(29, 1) ("authenticateCheckProxyAuthIP: broken or unknown auth type %d.\n", auth_user_request->auth_user->auth_type);
+           return 0;
+       }
+       username = authenticateUserRequestUsername(auth_user_request);
+       /* Update IP ttl */
+       auth_user_request->auth_user->ip_expiretime = squid_curtime;
+       auth_user_request->auth_user->ipaddr = request_src_addr;
+       return 1;
+    } else {
+       char *ip1 = xstrdup(inet_ntoa(auth_user_request->auth_user->ipaddr));
+       char *ip2 = xstrdup(inet_ntoa(request_src_addr));
+       if (Config.onoff.authenticateIpTTLStrict) {
+           debug(29, 1) ("aclMatchProxyAuth: user '%s' tried to use multiple IP addresses! (%s, %s)\n ", username, ip1, ip2);
+       } else {
+           /* Non-strict mode. Reassign ownership to the new IP */
+           auth_user_request->auth_user->ipaddr.s_addr = request_src_addr.s_addr;
+           debug(29, 1) ("aclMatchProxyAuth: user '%s' has changed IP address (%s, %s)\n ", username, ip1, ip2);
+       }
+       safe_free(ip1);
+       safe_free(ip2);
+       /* and deny access */
+       return 0;
+    }
 }
index 41aa3ed43ca63048de52ec2de67bb693a3478187..dab27b16ffb9dc559cc1425dd4a5d352b5a4aafd 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.cc,v 1.366 2001/01/05 09:51:36 adrian Exp $
+ * $Id: cache_cf.cc,v 1.367 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -63,14 +63,14 @@ static int parseTimeUnits(const char *unit);
 static void parseTimeLine(time_t * tptr, const char *units);
 static void parse_ushort(u_short * var);
 static void parse_string(char **);
-static void parse_wordlist(wordlist **);
+void parse_wordlist(wordlist **);
 static void default_all(void);
 static void defaults_if_none(void);
 static int parse_line(char *);
 static void parseBytesLine(size_t * bptr, const char *units);
 static size_t parseBytesUnits(const char *unit);
 static void free_all(void);
-static void requirePathnameExists(const char *name, const char *path);
+void requirePathnameExists(const char *name, const char *path);
 static OBJH dump_config;
 static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
 static void parse_http_header_access(header_mangler header[]);
@@ -303,17 +303,6 @@ configDoConfigure(void)
            Config.redirectChildren = DefaultRedirectChildrenMax;
        }
     }
-    if (Config.Program.authenticate) {
-       if (Config.authenticateChildren < 1) {
-           Config.authenticateChildren = 0;
-           wordlistDestroy(&Config.Program.authenticate);
-       } else if (Config.authenticateChildren > DefaultAuthenticateChildrenMax) {
-           debug(3, 0) ("WARNING: authenticate_children was set to a bad value: %d\n",
-               Config.authenticateChildren);
-           debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultAuthenticateChildrenMax);
-           Config.authenticateChildren = DefaultAuthenticateChildrenMax;
-       }
-    }
     if (Config.Accel.host) {
        snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
        Config2.Accel.prefix = xstrdup(buf);
@@ -369,8 +358,6 @@ configDoConfigure(void)
 #endif
     if (Config.Program.redirect)
        requirePathnameExists("redirect_program", Config.Program.redirect->key);
-    if (Config.Program.authenticate)
-       requirePathnameExists("authenticate_program", Config.Program.authenticate->key);
     requirePathnameExists("Icon Directory", Config.icons.directory);
     requirePathnameExists("Error Directory", Config.errorDirectory);
 #if HTTP_VIOLATIONS
@@ -923,6 +910,86 @@ check_null_string(char *s)
     return s == NULL;
 }
 
+void
+allocate_new_authScheme(authConfig * cfg)
+{
+    if (cfg->schemes == NULL) {
+       cfg->n_allocated = 4;
+       cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme));
+    }
+    if (cfg->n_allocated == cfg->n_configured) {
+       authScheme *tmp;
+       cfg->n_allocated <<= 1;
+       tmp = xcalloc(cfg->n_allocated, sizeof(authScheme));
+       xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
+       xfree(cfg->schemes);
+       cfg->schemes = tmp;
+    }
+}
+
+static void
+parse_authparam(authConfig * config)
+{
+    char *type_str;
+    char *param_str;
+    authScheme *scheme = NULL;
+    int type, i;
+
+    if ((type_str = strtok(NULL, w_space)) == NULL)
+       self_destruct();
+
+    if ((param_str = strtok(NULL, w_space)) == NULL)
+       self_destruct();
+
+    if ((type = authenticateAuthSchemeId(type_str)) == -1) {
+       debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
+       return;
+    }
+    for (i = 0; i < config->n_configured; i++) {
+       if (config->schemes[i].Id == type) {
+           scheme = config->schemes + i;
+       }
+    }
+
+    if (scheme == NULL) {
+       allocate_new_authScheme(config);
+       scheme = config->schemes + config->n_configured;
+       config->n_configured++;
+       scheme->Id = type;
+       scheme->typestr = authscheme_list[type].typestr;
+    }
+    authscheme_list[type].parse(scheme, config->n_configured, param_str);
+}
+
+static void
+free_authparam(authConfig * cfg)
+{
+    authScheme *scheme;
+    int i;
+    /* DON'T FREE THESE FOR RECONFIGURE */
+    if (reconfiguring)
+       return;
+    for (i = 0; i < cfg->n_configured; i++) {
+       scheme = cfg->schemes + i;
+       authscheme_list[scheme->Id].freeconfig(scheme);
+    }
+    safe_free(cfg->schemes);
+    cfg->schemes = NULL;
+    cfg->n_allocated = 0;
+    cfg->n_configured = 0;
+}
+
+static void
+dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
+{
+    authScheme *scheme;
+    int i;
+    for (i = 0; i < cfg.n_configured; i++) {
+       scheme = cfg.schemes + i;
+       authscheme_list[scheme->Id].dump(entry, name, scheme);
+    }
+}
+
 void
 allocate_new_swapdir(cacheSwap * swap)
 {
@@ -1423,7 +1490,7 @@ dump_int(StoreEntry * entry, const char *name, int var)
     storeAppendPrintf(entry, "%s %d\n", name, var);
 }
 
-static void
+void
 parse_int(int *var)
 {
     int i;
@@ -1620,7 +1687,7 @@ free_string(char **var)
     safe_free(*var);
 }
 
-static void
+void
 parse_eol(char *volatile *var)
 {
     char *token = strtok(NULL, null_string);
@@ -1636,7 +1703,7 @@ dump_time_t(StoreEntry * entry, const char *name, time_t var)
     storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
 }
 
-static void
+void
 parse_time_t(time_t * var)
 {
     parseTimeLine(var, T_SECOND_STR);
@@ -1729,7 +1796,7 @@ dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
     }
 }
 
-static void
+void
 parse_wordlist(wordlist ** list)
 {
     char *token;
@@ -1919,7 +1986,7 @@ configFreeMemory(void)
     free_all();
 }
 
-static void
+void
 requirePathnameExists(const char *name, const char *path)
 {
     struct stat sb;
index f6ea50eed2faec163403fbc8383863957b1f9061..81df59870eb3bee8a21f3d3d108398f3c24bc3c8 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cbdata.cc,v 1.33 2001/01/06 11:14:42 hno Exp $
+ * $Id: cbdata.cc,v 1.34 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 45    Callback Data Registry
  * ORIGINAL AUTHOR: Duane Wessels
@@ -137,6 +137,8 @@ cbdataInit(void)
     CREATE_CBDATA(generic_cbdata);
     CREATE_CBDATA(helper);
     CREATE_CBDATA(helper_server);
+    CREATE_CBDATA(statefulhelper);
+    CREATE_CBDATA(helper_stateful_server);
     CREATE_CBDATA(HttpStateData);
     CREATE_CBDATA(peer);
     CREATE_CBDATA(ps_state);
index 322ba34fa3056c6c0ed72f30f1bb4cf9d7ab3528..ff40101b1495b4c8fe19ce4afb9f53172b237a6d 100644 (file)
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.204 2001/01/04 21:09:00 wessels Exp $
+# $Id: cf.data.pre,v 1.205 2001/01/07 23:36:37 hno Exp $
 #
 #
 # SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -228,7 +228,7 @@ DOC_START
                     no-digest
                     no-netdb-exchange
                     no-delay
-                    login=user:password
+                    login=user:password|PASS
                     connect-timeout=nn
                     digest-url=url
                     allow-miss
@@ -280,6 +280,13 @@ DOC_START
                     use 'login=user:password' if this is a personal/workgroup
                     proxy and your parent requires proxy authentication.
 
+                    use 'login=PASS' if users must authenticate against
+                    the upstream proxy. Note: To combine this with
+                    proxy_auth both proxies must share the same user
+                    database as HTTP only allows for one proxy login.
+                    Also be warned that this will expose your users proxy
+                    password to the parent. USE WITH CAUTION
+
                     use 'connect-timeout=nn' to specify a peer
                     specific connect timeout (also see the
                     peer_connect_timeout directive)
@@ -1104,17 +1111,35 @@ DOC_START
        are sent.
 DOC_END
 
-
-NAME: authenticate_program
-TYPE: wordlist
-LOC: Config.Program.authenticate
+NAME: auth_param
+TYPE: authparam
+LOC: Config.authConfig
 DEFAULT: none
 DOC_START
+       This is used to pass parameters to the various authentication
+       schemes.
+       format: auth_param scheme parameter [setting]
+       
+       auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd     
+       would tell the basic authentication scheme it's program parameter.
+
+       The order that authentication prompts are presented to the client_agent
+       is dependant on the order the scheme first appears in config file.
+       IE has a bug (it's not rfc 2617 compliant) in that it will use the basic
+       scheme if basic is the first entry presented, even if more secure schemes
+       are presented. For now use the order in the file below. If other browsers
+       have difficulties (don't recognise the schemes offered even if you are using
+       basic) then either put basic first, or disable the other schemes (by commenting
+       out their program entry).
+
+       === Parameters for the basic scheme follow. ===
+       
+       "program" cmdline
        Specify the command for the external authenticator.  Such a
        program reads a line containing "username password" and replies
        "OK" or "ERR" in an endless loop.  If you use an authenticator,
        make sure you have 1 acl of type proxy_auth.  By default, the
-       authenticator_program is not used.
+       authenticate_program is not used.
 
        If you want to use the traditional proxy authentication,
        jump over to the ../auth_modules/NCSA directory and
@@ -1124,19 +1149,87 @@ DOC_START
 
        Then, set this line to something like
 
-       authenticate_program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd
-DOC_END
+       auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd
 
-NAME: authenticate_children
-TYPE: int
-DEFAULT: 5
-LOC: Config.authenticateChildren
-DOC_START
-       The number of authenticator processes to spawn (default 5). If you
+       "children" numberofchildren
+       The number of authenticator processes to spawn (no default). If you
        start too few Squid will have to wait for them to process a backlog
        of usercode/password verifications, slowing it down. When password
        verifications are done via a (slow) network you are likely to need
        lots of authenticator processes.
+       auth_param basic children 5
+
+       "realm" realmstring
+       Specifies the realm name which is to be reported to the client for
+       the basic proxy authentication scheme (part of the text the user will
+       see when prompted their username and password). Their is no default.
+       auth_param basic realm Squid proxy-caching web server
+
+       "credentialsttl" timetolive
+       Specifies how long squid assumes an externally validated username:password
+       pair is valid for - in other words how often the helper program is called 
+       for that user. Set this low to force revalidation with short lived passwords.
+       Note that setting this high does not impact your susceptability to replay
+       attacks unless you are using a one-time password system (such as SecureID).
+       If you are using such a system, you will be vulnerable to replay attacks
+       unless you also enable the IP ttl is strict option.
+
+       === NTLM scheme options follow ===
+
+       "program" cmdline
+       Specify the command for the external ntlm authenticator.  Such a
+       program reads a line containing the uuencoded NEGOTIATE and replies
+       with the ntlm CHALLENGE, then waits for the response and answers with
+       "OK" or "ERR" in an endless loop.  If you use an ntlm authenticator,
+       make sure you have 1 acl of type proxy_auth.  By default, the
+       ntlm authenticator_program is not used.
+
+       auth_param ntlm program @DEFAULT_PREFIX@/bin/ntlm_auth
+
+       "children" numberofchildren
+       The number of authenticator processes to spawn (no default). If you
+       start too few Squid will have to wait for them to process a backlog
+       of credential verifications, slowing it down. When crendential
+       verifications are done via a (slow) network you are likely to need
+       lots of authenticator processes.
+       auth_param ntlm children 5
+
+       "max_challenge_reuses" number
+       The maximum number of times a challenge given by a ntlm authentication
+       helper can be reused. Increasing this number increases your exposure 
+       to replay attacks on your network. 0 means use the challenge only once. 
+       (disable challenge caching)
+       See max_ntlm_challenge_lifetime for more information.
+       auth_param ntlm max_challenge_reuses 0
+
+       "max_challenge_lifetime" timespan
+       The maximum time period that a ntlm challenge is reused over.
+       The actual period will be the minimum of this time AND the number of 
+       reused challenges.
+       auth_param ntlm max_challenge_lifetime 2 minutes
+
+NOCOMMENT_START
+#Recommended minimum configuration:
+#auth_param ntlm program <uncomment and complete this line to activate>
+auth_param ntlm children 5
+auth_param ntlm max_challenge_reuses 0
+auth_param ntlm max_challenge_lifetime 2 minutes
+#auth_param basic program <uncomment and complete this line>
+auth_param basic children 5
+auth_param basic realm Squid proxy-caching web server
+auth_param basic credentialsttl 2 hours
+NOCOMMENT_END
+DOC_END
+
+NAME: authenticate_cache_garbage_interval
+TYPE: time_t
+DEFAULT: 1 hour
+LOC: Config.authenticateGCInterval
+DOC_START
+       The time period between garbage collection across the username cache. 
+       This is a tradeoff between memory utilisation (long intervals - say
+       2 days) and CPU (short intervals - say 1 minute). Only change if
+       you have good reason to.
 DOC_END
 
 NAME: authenticate_ttl
@@ -1144,9 +1237,9 @@ TYPE: time_t
 DEFAULT: 1 hour
 LOC: Config.authenticateTTL
 DOC_START
-       The time a checked username/password combination remains cached.
-       If a wrong password is given for a cached user, the user gets
-       removed from the username/password cache forcing a revalidation.
+       The time a user & their credentials stay in the logged in user cache
+       since their last request. When the garbage interval passes, all
+       user credentials that have passed their TTL are removed from memory.
 DOC_END
 
 NAME: authenticate_ip_ttl
@@ -1176,7 +1269,7 @@ TYPE: onoff
 LOC: Config.onoff.authenticateIpTTLStrict
 DEFAULT: on
 DOC_START
-       This option makes authenticate_ip_ttl a bit stricted. With this
+       This option makes authenticate_ip_ttl a bit stricter. With this
        enabled authenticate_ip_ttl will deny all access from other IP
        addresses until the TTL has expired, and the IP address "owning"
        the userid will not be forced to reauthenticate.
@@ -1824,17 +1917,6 @@ DOC_START
        the Squid FAQ (http://squid.nlanr.net/Squid/FAQ/FAQ-10.html).
 DOC_END
 
-NAME: proxy_auth_realm
-TYPE: eol
-DEFAULT: Squid proxy-caching web server
-LOC: Config.proxyAuthRealm
-DOC_START
-       Specifies the realm name which is to be reported to the client for
-       proxy authentication (part of the text the user will see when
-       prompted their username and password).
-DOC_END
-
-
 NAME: ident_lookup_access
 TYPE: acl_access
 IFDEF: USE_IDENT
index 97d067586ab5a4ef9905b6e33b04309de46e4b2f..c9db0e5eb1c9a55b7b8239ed7b6903d252381d23 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.cc,v 1.521 2001/01/05 09:51:36 adrian Exp $
+ * $Id: client_side.cc,v 1.522 2001/01/07 23:36:37 hno Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -116,6 +116,7 @@ static DEFER httpAcceptDefer;
 static log_type clientProcessRequest2(clientHttpRequest * http);
 static int clientReplyBodyTooLarge(int clen);
 static int clientRequestBodyTooLarge(int clen);
+static void clientProcessBody(ConnStateData * conn);
 
 static int
 checkAccelOnly(clientHttpRequest * http)
@@ -138,11 +139,9 @@ static void
 clientIdentDone(const char *ident, void *data)
 {
     ConnStateData *conn = data;
-    if (ident)
-       xstrncpy(conn->ident, ident, sizeof(conn->ident));
-    else
-       xstrncpy(conn->ident, "-", sizeof(conn->ident));
+    xstrncpy(conn->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
 }
+
 #endif
 
 static aclCheck_t *
@@ -152,15 +151,16 @@ clientAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
     ConnStateData *conn = http->conn;
     ch = aclChecklistCreate(acl,
        http->request,
-       conn->ident);
-#if USE_IDENT
+       conn->rfc931);
+
     /*
      * hack for ident ACL. It needs to get full addresses, and a
      * place to store the ident result on persistent connections...
      */
+    /* connection oriented auth also needs these two lines for it's operation. */
     ch->conn = conn;
     cbdataLock(ch->conn);
-#endif
+
     return ch;
 }
 
@@ -223,8 +223,7 @@ clientAccessCheckDone(int answer, void *data)
        RequestMethodStr[http->request->method], http->uri,
        answer == ACCESS_ALLOWED ? "ALLOWED" : "DENIED",
        AclMatchedName ? AclMatchedName : "NO ACL's");
-    if (http->acl_checklist->auth_user)
-       proxy_auth_msg = http->acl_checklist->auth_user->message;
+    proxy_auth_msg = authenticateAuthUserRequestMessage(http->conn->auth_user_request ? http->conn->auth_user_request : http->request->auth_user_request);
     http->acl_checklist = NULL;
     if (answer == ACCESS_ALLOWED) {
        safe_free(http->uri);
@@ -266,7 +265,13 @@ clientAccessCheckDone(int answer, void *data)
        err = errorCon(page_id, status);
        err->request = requestLink(http->request);
        err->src_addr = http->conn->peer.sin_addr;
-       err->proxy_auth_msg = proxy_auth_msg;
+       if (http->conn->auth_user_request)
+           err->auth_user_request = http->conn->auth_user_request;
+       else if (http->request->auth_user_request)
+           err->auth_user_request = http->request->auth_user_request;
+       /* lock for the error state */
+       if (err->auth_user_request)
+           authenticateAuthUserRequestLock(err->auth_user_request);
        err->callback_data = NULL;
        errorAppendEntry(http->entry, err);
     }
@@ -305,13 +310,10 @@ clientRedirectDone(void *data, char *result)
        new_request->my_addr = old_request->my_addr;
        new_request->my_port = old_request->my_port;
        new_request->flags.redirected = 1;
-       if (old_request->user_ident[0])
-           xstrncpy(new_request->user_ident, old_request->user_ident,
-               USER_IDENT_SZ);
-       if (old_request->body) {
-           new_request->body = xmalloc(old_request->body_sz);
-           xmemcpy(new_request->body, old_request->body, old_request->body_sz);
-           new_request->body_sz = old_request->body_sz;
+       new_request->auth_user_request = old_request->auth_user_request;
+       if (old_request->body_connection) {
+           new_request->body_connection = old_request->body_connection;
+           old_request->body_connection = NULL;
        }
        new_request->content_length = old_request->content_length;
        new_request->flags.proxy_keepalive = old_request->flags.proxy_keepalive;
@@ -706,6 +708,8 @@ httpRequestFree(void *data)
     MemObject *mem = NULL;
     debug(33, 3) ("httpRequestFree: %s\n", storeUrl(http->entry));
     if (!clientCheckTransferDone(http)) {
+       if (request && request->body_connection)
+           clientAbortBody(request);   /* abort body transter */
 #if MYSTERIOUS_CODE
        /*
         * DW: this seems odd here, is it really needed?  It causes
@@ -746,10 +750,13 @@ httpRequestFree(void *data)
            http->al.http.version = request->http_ver;
            http->al.headers.request = xstrdup(mb.buf);
            http->al.hier = request->hier;
-           if (request->user_ident[0])
-               http->al.cache.ident = request->user_ident;
-           else
-               http->al.cache.ident = conn->ident;
+           if (request->auth_user_request) {
+               http->al.cache.authuser = xstrdup(authenticateUserRequestUsername(request->auth_user_request));
+               authenticateAuthUserRequestUnlock(request->auth_user_request);
+               request->auth_user_request = NULL;
+           }
+           if (conn->rfc931[0])
+               http->al.cache.rfc931 = conn->rfc931;
            packerClean(&p);
            memBufClean(&mb);
        }
@@ -784,6 +791,7 @@ httpRequestFree(void *data)
     requestUnlink(http->request);
     assert(http != http->next);
     assert(http->conn->chr != NULL);
+    /* Unlink us from the clients request list */
     H = &http->conn->chr;
     while (*H) {
        if (*H == http)
@@ -805,6 +813,7 @@ connStateFree(int fd, void *data)
     clientHttpRequest *http;
     debug(33, 3) ("connStateFree: FD %d\n", fd);
     assert(connState != NULL);
+    authenticateOnCloseConnection(connState);
     clientdbEstablished(connState->peer.sin_addr, -1); /* decrement */
     while ((http = connState->chr) != NULL) {
        assert(http->conn == connState);
@@ -986,14 +995,18 @@ clientCachable(clientHttpRequest * http)
     if (req->protocol == PROTO_HTTP)
        return httpCachable(method);
     /* FTP is always cachable */
-    if (req->protocol == PROTO_GOPHER)
-       return gopherCachable(url);
     if (req->protocol == PROTO_WAIS)
        return 0;
     if (method == METHOD_CONNECT)
        return 0;
     if (method == METHOD_TRACE)
        return 0;
+    if (method == METHOD_PUT)
+       return 0;
+    if (method == METHOD_POST)
+       return 0;               /* XXX POST may be cached sometimes.. ignored for now */
+    if (req->protocol == PROTO_GOPHER)
+       return gopherCachable(url);
     if (req->protocol == PROTO_CACHEOBJ)
        return 0;
     return 1;
@@ -1272,6 +1285,9 @@ clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep)
                httpHeaderPutInt(hdr, HDR_AGE,
                    squid_curtime - http->entry->timestamp);
     }
+    /* Handle authentication headers */
+    if (request->auth_user_request)
+       authenticateFixHeader(rep, request->auth_user_request, request, http->flags.accel);
     /* Append X-Cache */
     httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
        is_hit ? "HIT" : "MISS", getMyHostname());
@@ -1853,7 +1869,7 @@ clientKeepaliveNextRequest(clientHttpRequest * http)
     if ((http = conn->chr) == NULL) {
        debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next req\n",
            conn->fd);
-       fd_note(conn->fd, "Reading next request");
+       fd_note(conn->fd, "Waiting for next request");
        /*
         * Set the timeout BEFORE calling clientReadRequest().
         */
@@ -2135,13 +2151,6 @@ clientProcessRequest(clientHttpRequest * http)
        }
        /* yes, continue */
        http->log_type = LOG_TCP_MISS;
-    } else if (r->content_length >= 0) {
-       /*
-        * Need to initialize pump even if content-length: 0
-        */
-       http->log_type = LOG_TCP_MISS;
-       /* XXX oof, POST can be cached! */
-       pumpInit(fd, r, http->uri);
     } else {
        http->log_type = clientProcessRequest2(http);
     }
@@ -2509,7 +2518,10 @@ static int
 clientReadDefer(int fdnotused, void *data)
 {
     ConnStateData *conn = data;
-    return conn->defer.until > squid_curtime;
+    if (conn->body.size_left)
+       return conn->in.offset >= conn->in.size;
+    else
+       return conn->defer.until > squid_curtime;
 }
 
 static void
@@ -2542,14 +2554,18 @@ clientReadRequest(int fd, void *data)
      * whole, not individual read() calls.  Plus, it breaks our
      * lame half-close detection
      */
-    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
-    if (size == 0) {
-       if (conn->chr == NULL) {
+    if (size > 0) {
+       conn->in.offset += size;
+       conn->in.buf[conn->in.offset] = '\0';   /* Terminate the string */
+    } else if (size == 0 && len > 0) {
+       if (conn->chr == NULL && conn->in.offset == 0) {
            /* no current or pending requests */
+           debug(33, 4) ("clientReadRequest: FD %d closed\n", fd);
            comm_close(fd);
            return;
        } else if (!Config.onoff.half_closed_clients) {
            /* admin doesn't want to support half-closed client sockets */
+           debug(33, 3) ("clientReadRequest: FD %d aborted (half_closed_clients disabled)\n", fd);
            comm_close(fd);
            return;
        }
@@ -2559,7 +2575,11 @@ clientReadRequest(int fd, void *data)
        conn->defer.until = squid_curtime + 1;
        conn->defer.n++;
        fd_note(fd, "half-closed");
-       return;
+       /* There is one more close check at the end, to detect aborted
+        * (partial) requests. At this point we can't tell if the request
+        * is partial.
+        */
+       /* Continue to process previously read data */
     } else if (size < 0) {
        if (!ignoreErrno(errno)) {
            debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror());
@@ -2570,13 +2590,16 @@ clientReadRequest(int fd, void *data)
            return;
        }
        /* Continue to process previously read data */
-       size = 0;
     }
-    conn->in.offset += size;
-    /* Skip leading (and trailing) whitespace */
-    while (conn->in.offset > 0) {
+    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
+    /* Process request body if any */
+    if (conn->in.offset > 0 && conn->body.callback != NULL)
+       clientProcessBody(conn);
+    /* Process next request */
+    while (conn->in.offset > 0 && conn->body.size_left == 0) {
        int nrequests;
        size_t req_line_sz;
+       /* Skip leading (and trailing) whitespace */
        while (conn->in.offset > 0 && xisspace(conn->in.buf[0])) {
            xmemmove(conn->in.buf, conn->in.buf + 1, conn->in.offset - 1);
            conn->in.offset--;
@@ -2592,6 +2615,9 @@ clientReadRequest(int fd, void *data)
            conn->defer.until = squid_curtime + 100;    /* Reset when a request is complete */
            break;
        }
+       conn->in.buf[conn->in.offset] = '\0';   /* Terminate the string */
+       if (nrequests == 0)
+           fd_note(conn->fd, "Reading next request");
        /* Process request */
        http = parseHttpRequest(conn,
            &method,
@@ -2686,7 +2712,7 @@ clientReadRequest(int fd, void *data)
                errorAppendEntry(http->entry, err);
                break;
            }
-           if (0 == clientCheckContentLength(request)) {
+           if (!clientCheckContentLength(request)) {
                err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
                err->src_addr = conn->peer.sin_addr;
                err->request = requestLink(request);
@@ -2696,38 +2722,13 @@ clientReadRequest(int fd, void *data)
                break;
            }
            http->request = requestLink(request);
-           /*
-            * We need to set the keepalive flag before doing some
-            * hacks for POST/PUT requests below.  Maybe we could
-            * set keepalive flag even earlier.
-            */
            clientSetKeepaliveFlag(http);
-           /*
-            * break here if the request has a content-length
-            * because there is a reqeust body following and we
-            * don't want to parse it as though it was new request.
-            */
-           if (request->content_length >= 0) {
-               int copy_len = XMIN(conn->in.offset, request->content_length);
-               if (copy_len > 0) {
-                   assert(conn->in.offset >= copy_len);
-                   request->body_sz = copy_len;
-                   request->body = xmalloc(request->body_sz);
-                   xmemcpy(request->body, conn->in.buf, request->body_sz);
-                   conn->in.offset -= copy_len;
-                   if (conn->in.offset)
-                       xmemmove(conn->in.buf, conn->in.buf + copy_len, conn->in.offset);
-               }
-               /*
-                * if we didn't get the full body now, then more will
-                * be arriving on the client socket.  Lets cancel
-                * the read handler until this request gets forwarded.
-                */
-               if (request->body_sz < request->content_length)
-                   commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
-               if (request->content_length < 0)
-                   (void) 0;
-               else if (clientRequestBodyTooLarge(request->content_length)) {
+           /* Do we expect a request-body? */
+           if (request->content_length > 0) {
+               conn->body.size_left = request->content_length;
+               request->body_connection = conn;
+               /* Is it too large? */
+               if (clientRequestBodyTooLarge(request->content_length)) {
                    err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
                    err->request = requestLink(request);
                    http->entry = clientCreateStoreEntry(http,
@@ -2737,7 +2738,7 @@ clientReadRequest(int fd, void *data)
                }
            }
            clientAccessCheck(http);
-           continue;           /* while offset > 0 */
+           continue;           /* while offset > 0 && body.size_left == 0 */
        } else if (parser_return_code == 0) {
            /*
             *    Partial request received; reschedule until parseHttpRequest()
@@ -2776,7 +2777,132 @@ clientReadRequest(int fd, void *data)
            }
            break;
        }
+    }                          /* while offset > 0 && conn->body.size_left == 0 */
+    /* Check if a half-closed connection was aborted in the middle */
+    if (F->flags.socket_eof) {
+       if (conn->in.offset != conn->body.size_left) {  /* != 0 when no request body */
+           /* Partial request received. Abort client connection! */
+           debug(33, 3) ("clientReadRequest: FD %d aborted\n", fd);
+           comm_close(fd);
+           return;
+       }
+    }
+}
+
+/* file_read like function, for reading body content */
+void
+clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
+{
+    ConnStateData *conn = request->body_connection;
+    if (!conn) {
+       debug(33, 5) ("clientReadBody: no body to read, request=%p\n", request);
+       callback(buf, 0, cbdata);       /* Signal end of body */
+       return;
     }
+    debug(33, 2) ("clientReadBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
+    conn->body.callback = callback;
+    conn->body.cbdata = cbdata;
+    conn->body.buf = buf;
+    conn->body.bufsize = size;
+    conn->body.request = requestLink(request);
+    if (conn->in.offset) {
+       /* Data available */
+       clientProcessBody(conn);
+    } else {
+       debug(33, 2) ("clientReadBody: fd %d wait for clientReadRequest\n", conn->fd);
+    }
+}
+
+/* Called by clientReadRequest to process body content */
+static void
+clientProcessBody(ConnStateData * conn)
+{
+    int size;
+    char *buf = conn->body.buf;
+    void *cbdata = conn->body.cbdata;
+    CBCB *callback = conn->body.callback;
+    request_t *request = conn->body.request;
+    /* Note: request is null while eating "aborted" transfers */
+    debug(33, 2) ("clientProcessBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
+    /* Some sanity checks... */
+    assert(conn->body.size_left > 0);
+    assert(conn->in.offset > 0);
+    assert(callback != NULL);
+    assert(buf != NULL);
+    /* How much do we have to process? */
+    size = conn->in.offset;
+    if (size > conn->body.size_left)   /* only process the body part */
+       size = conn->body.size_left;
+    if (size > conn->body.bufsize)     /* don't copy more than requested */
+       size = conn->body.bufsize;
+    xmemcpy(buf, conn->in.buf, size);
+    conn->body.size_left -= size;
+    /* Move any remaining data */
+    conn->in.offset -= size;
+    if (conn->in.offset > 0)
+       xmemmove(conn->in.buf, conn->in.buf + size, conn->in.offset);
+    /* Remove request link if this is the last part of the body, as
+     * clientReadRequest automatically continues to process next request */
+    if (conn->body.size_left <= 0 && request != NULL)
+       request->body_connection = NULL;
+    /* Remove clientReadBody arguments (the call is completed) */
+    conn->body.request = NULL;
+    conn->body.callback = NULL;
+    conn->body.buf = NULL;
+    conn->body.bufsize = 0;
+    /* Remember that we have touched the body, not restartable */
+    if (request != NULL)
+       request->flags.body_sent = 1;
+    /* Invoke callback function */
+    callback(buf, size, cbdata);
+    if (request != NULL)
+       requestUnlink(request); /* Linked in clientReadBody */
+    debug(33, 2) ("clientProcessBody: end fd=%d size=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, size, conn->body.size_left, conn->in.offset, callback, request);
+    return;
+}
+
+/* A dummy handler that throws away a request-body */
+static char bodyAbortBuf[SQUID_TCP_SO_RCVBUF];
+void
+clientReadBodyAbortHandler(char *buf, size_t size, void *data)
+{
+    ConnStateData *conn = (ConnStateData *) data;
+    debug(33, 2) ("clientReadBodyAbortHandler: fd=%d body_size=%d in.offset=%d\n", conn->fd, conn->body.size_left, conn->in.offset);
+    if (size != 0 && conn->body.size_left != 0) {
+       debug(33, 3) ("clientReadBodyAbortHandler: fd=%d shedule next read\n", conn->fd);
+       conn->body.callback = clientReadBodyAbortHandler;
+       conn->body.buf = bodyAbortBuf;
+       conn->body.bufsize = sizeof(bodyAbortBuf);
+       conn->body.cbdata = data;
+    }
+}
+
+/* Abort a body request */
+int
+clientAbortBody(request_t * request)
+{
+    ConnStateData *conn = request->body_connection;
+    char *buf;
+    CBCB *callback;
+    void *cbdata;
+    request->body_connection = NULL;
+    if (!conn || conn->body.size_left <= 0)
+       return 0;               /* No body to abort */
+    if (conn->body.callback != NULL) {
+       buf = conn->body.buf;
+       callback = conn->body.callback;
+       cbdata = conn->body.cbdata;
+       assert(request == conn->body.request);
+       conn->body.buf = NULL;
+       conn->body.callback = NULL;
+       conn->body.cbdata = NULL;
+       conn->body.request = NULL;
+       callback(buf, -1, cbdata);      /* Signal abort to clientReadBody caller */
+       requestUnlink(request);
+    }
+    clientReadBodyAbortHandler(NULL, -1, conn);                /* Install abort handler */
+    /* clientProcessBody() */
+    return 1;                  /* Aborted */
 }
 
 /* general lifetime handler for HTTP requests */
index 0abde80070d62a946e8115bca71a37847071df5a..70b066e6fcd7ca3f632fe0bab3a1844c33cef259 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: defines.h,v 1.87 2001/01/06 11:41:37 hno Exp $
+ * $Id: defines.h,v 1.88 2001/01/07 23:36:38 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -53,7 +53,6 @@
 
 #define DefaultDnsChildrenMax          32      /* 32 processes */
 #define DefaultRedirectChildrenMax     32      /* 32 processes */
-#define DefaultAuthenticateChildrenMax 32      /* 32 processes */
 #define MAXHTTPPORTS                   12
 
 #define COMM_OK                  (0)
 #define REDIRECT_DONE 2
 
 #define AUTHENTICATE_AV_FACTOR 1000
+/* AUTHENTICATION */
 
-#define AUTHENTICATE_NONE 0
-#define AUTHENTICATE_PENDING 1
-#define AUTHENTICATE_DONE 2
+#define NTLM_CHALLENGE_SZ 300
 
 #define  CONNECT_PORT        443
 
index cbb452877afc5a2517b19d7957bc8c4636b0c2da..c1fa7158890a440c4fbb834ea58ef9f7b7b67805 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.181 2001/01/07 20:11:18 hno Exp $
+ * $Id: enums.h,v 1.182 2001/01/07 23:36:38 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -130,7 +130,7 @@ typedef enum {
     ACL_LOOKUP_NEEDED,
     ACL_LOOKUP_PENDING,
     ACL_LOOKUP_DONE,
-    ACL_PROXY_AUTH_NEEDED
+    ACL_PROXY_AUTH_NEEDED,
 } acl_lookup_state;
 
 enum {
@@ -492,6 +492,37 @@ typedef enum {
     ACCESS_REQ_PROXY_AUTH
 } allow_t;
 
+typedef enum {
+    AUTH_UNKNOWN,              /* default */
+    AUTH_BASIC,
+    AUTH_NTLM,
+    AUTH_BROKEN                        /* known type, but broken data */
+} auth_type_t;
+
+typedef enum {
+    AUTHENTICATE_STATE_NONE,
+    AUTHENTICATE_STATE_NEGOTIATE,
+    AUTHENTICATE_STATE_CHALLENGE,
+    AUTHENTICATE_STATE_RESPONSE,
+    AUTHENTICATE_STATE_DONE
+} auth_state_t;                        /* connection level auth state */
+
+/* stateful helper callback response codes */
+typedef enum {
+    S_HELPER_UNKNOWN,
+    S_HELPER_RESERVE,
+    S_HELPER_RELEASE,
+    S_HELPER_DEFER
+} stateful_helper_callback_t;
+
+/* stateful helper reservation info */
+typedef enum {
+    S_HELPER_FREE,             /* available for requests */
+    S_HELPER_RESERVED,         /* in a reserved state - no active request, but state data in the helper shouldn't be disturbed */
+    S_HELPER_DEFERRED          /* available for requests, and at least one more will come from a previous caller with the server pointer */
+} stateful_helper_reserve_t;
+
+
 #if SQUID_SNMP
 enum {
     SNMP_C_VIEW,
@@ -517,8 +548,10 @@ typedef enum {
     MEM_ACL_IP_DATA,
     MEM_ACL_LIST,
     MEM_ACL_NAME_LIST,
+    MEM_AUTH_USER_T,
+    MEM_AUTH_USER_HASH,
+    MEM_ACL_PROXY_AUTH_MATCH,
     MEM_ACL_USER_DATA,
-    MEM_ACL_PROXY_AUTH_USER,
     MEM_ACL_TIME_DATA,
     MEM_CACHEMGR_PASSWD,
 #if USE_CACHE_DIGESTS
@@ -551,8 +584,11 @@ typedef enum {
     MEM_HASH_LINK,
     MEM_HASH_TABLE,
     MEM_HELPER,
-    MEM_HELPER_REQUEST,
+    MEM_HELPER_STATEFUL,
     MEM_HELPER_SERVER,
+    MEM_HELPER_STATEFUL_SERVER,
+    MEM_HELPER_REQUEST,
+    MEM_HELPER_STATEFUL_REQUEST,
     MEM_HIERARCHYLOGENTRY,
 #if USE_HTCP
     MEM_HTCP_SPECIFIER,
@@ -609,6 +645,9 @@ typedef enum {
     MEM_PUMP_STATE_DATA,
     MEM_CLIENT_REQ_BUF,
     MEM_MAX
+#ifdef NTLM_CACHING
+    ,MEM_NTLM_AUTH_CACHE
+#endif
 } mem_type;
 
 /*
@@ -696,6 +735,8 @@ typedef enum {
     CBDATA_generic_cbdata,
     CBDATA_helper,
     CBDATA_helper_server,
+    CBDATA_statefulhelper,
+    CBDATA_helper_stateful_server,
     CBDATA_HttpStateData,
     CBDATA_peer,
     CBDATA_ps_state,
index 365df2c3c5e5357464e1c1b3c6b9046f66221029..e63b7aea28a64a04fa714e6d8190096fd439b7b4 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: errorpage.cc,v 1.160 2001/01/05 09:51:37 adrian Exp $
+ * $Id: errorpage.cc,v 1.161 2001/01/07 23:36:38 hno Exp $
  *
  * DEBUG: section 4     Error Generation
  * AUTHOR: Duane Wessels
@@ -52,8 +52,6 @@ typedef struct {
 
 /* local constant and vars */
 
-static const char *const proxy_auth_challenge_fmt = "Basic realm=\"%s\"";
-
 /*
  * note: hard coded error messages are not appended with %S automagically
  * to give you more control on the format
@@ -280,25 +278,13 @@ errorAppendEntry(StoreEntry * entry, ErrorState * err)
     storeBuffer(entry);
     rep = errorBuildReply(err);
     /* Add authentication header */
-    switch (err->http_status) {
-    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
-       /* Proxy authorisation needed */
-       httpHeaderPutStrf(&rep->header, HDR_PROXY_AUTHENTICATE,
-           proxy_auth_challenge_fmt, Config.proxyAuthRealm);
-       break;
-    case HTTP_UNAUTHORIZED:
-       /* WWW Authorisation needed */
-       httpHeaderPutStrf(&rep->header, HDR_WWW_AUTHENTICATE,
-           proxy_auth_challenge_fmt, Config.proxyAuthRealm);
-       break;
-    default:
-       /* Keep GCC happy */
-       break;
-    }
+    /* TODO: alter errorstate to be accel on|off aware. The 0 on the next line
+     * depends on authenticate behaviour: all schemes to date send no extra data
+     * on 407/401 responses, and do not check the accel state on 401/407 responses 
+     */
+    authenticateFixHeader(rep, err->auth_user_request, err->request, 0);
     httpReplySwapOut(rep, entry);
-    httpReplyDestroy(rep);
-    mem->reply->sline.status = err->http_status;
-    mem->reply->content_length = -1;
+    httpReplyAbsorb(mem->reply, rep);
     EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
     storeBufferFlush(entry);
     storeComplete(entry);
@@ -361,10 +347,13 @@ errorSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data
     ErrorState *err = data;
     debug(4, 3) ("errorSendComplete: FD %d, size=%d\n", fd, size);
     if (errflag != COMM_ERR_CLOSING) {
-       if (err->callback)
+       if (err->callback) {
+           debug(4, 3) ("errorSendComplete: callback\n");
            err->callback(fd, err->callback_data, size);
-       else
+       } else {
            comm_close(fd);
+           debug(4, 3) ("errorSendComplete: comm_close\n");
+       }
     }
     errorStateFree(err);
 }
@@ -377,11 +366,12 @@ errorStateFree(ErrorState * err)
     safe_free(err->url);
     safe_free(err->host);
     safe_free(err->dnsserver_msg);
-    safe_free(err->proxy_auth_msg);
     safe_free(err->request_hdrs);
     wordlistDestroy(&err->ftp.server_msg);
     safe_free(err->ftp.request);
     safe_free(err->ftp.reply);
+    if (err->auth_user_request)
+       authenticateAuthUserRequestUnlock(err->auth_user_request);
     cbdataFree(err);
 }
 
@@ -483,7 +473,7 @@ errorConvert(char token, ErrorState * err)
            p = "[not available]";
        break;
     case 'm':
-       p = err->proxy_auth_msg ? err->proxy_auth_msg : "[not available]";
+       p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]";
        break;
     case 'M':
        p = r ? RequestMethodStr[r->method] : "[unkown method]";
index 887dcb105fc3136a594412e6445fbfccc947a7a0..aec80d1af5cf3701f3fcfe8a3af1b53025f4660f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: forward.cc,v 1.78 2001/01/05 09:51:37 adrian Exp $
+ * $Id: forward.cc,v 1.79 2001/01/07 23:36:38 hno Exp $
  *
  * DEBUG: section 17    Request Forwarding
  * AUTHOR: Duane Wessels
@@ -138,9 +138,8 @@ fwdCheckRetry(FwdState * fwdState)
        return 0;
     if (fwdState->flags.dont_retry)
        return 0;
-    if (fwdState->request->content_length >= 0)
-       if (0 == pumpRestart(fwdState->request))
-           return 0;
+    if (fwdState->request->flags.body_sent)
+       return 0;
     return 1;
 }
 
@@ -392,6 +391,7 @@ fwdDispatch(FwdState * fwdState)
        fwdState->request->peer_login = p->login;
        httpStart(fwdState);
     } else {
+       fwdState->request->peer_login = NULL;
        switch (request->protocol) {
        case PROTO_HTTP:
            httpStart(fwdState);
@@ -459,9 +459,8 @@ fwdReforward(FwdState * fwdState)
     }
     if (fwdState->n_tries > 9)
        return 0;
-    if (fwdState->request->content_length >= 0)
-       if (0 == pumpRestart(fwdState->request))
-           return 0;
+    if (fwdState->request->flags.body_sent)
+       return 0;
     assert(fs);
     fwdState->servers = fs->next;
     fwdServerFree(fs);
index 917ce5b8056e0d9af7f76b5ac1ffbc5dc8ec88bb..19d4d8612c695325293a0f7fdfb1c1c3b8da1c52 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ftp.cc,v 1.304 2001/01/07 10:57:15 hno Exp $
+ * $Id: ftp.cc,v 1.305 2001/01/07 23:36:38 hno Exp $
  *
  * DEBUG: section 9     File Transfer Protocol (FTP)
  * AUTHOR: Harvest Derived
@@ -148,8 +148,9 @@ typedef void (FTPSM) (FtpStateData *);
 /* Local functions */
 static CNCB ftpPasvCallback;
 static PF ftpDataRead;
+static PF ftpDataWrite;
+static CWCB ftpDataWriteCallback;
 static PF ftpStateFree;
-static PF ftpPumpClosedData;
 static PF ftpTimeout;
 static PF ftpReadControlReply;
 static CWCB ftpWriteCommandCallback;
@@ -159,8 +160,6 @@ static int ftpRestartable(FtpStateData * ftpState);
 static void ftpAppendSuccessHeader(FtpStateData * ftpState);
 static void ftpAuthRequired(HttpReply * reply, request_t * request, const char *realm);
 static void ftpHackShortcut(FtpStateData * ftpState, FTPSM * nextState);
-static void ftpPutStart(FtpStateData *);
-static CWCB ftpPutTransferDone;
 static void ftpUnhack(FtpStateData * ftpState);
 static void ftpScheduleReadControlReply(FtpStateData *, int);
 static void ftpHandleControlReply(FtpStateData *);
@@ -194,6 +193,7 @@ static FTPSM ftpListDir;
 static FTPSM ftpGetFile;
 static FTPSM ftpSendCwd;
 static FTPSM ftpReadCwd;
+static FTPSM ftpRestOrList;
 static FTPSM ftpSendList;
 static FTPSM ftpSendNlst;
 static FTPSM ftpReadList;
@@ -202,16 +202,15 @@ static FTPSM ftpReadRest;
 static FTPSM ftpSendRetr;
 static FTPSM ftpReadRetr;
 static FTPSM ftpReadTransferDone;
-static FTPSM ftpSendQuit;
-static FTPSM ftpReadQuit;
-static FTPSM ftpFail;
-static FTPSM ftpDataTransferDone;
-static FTPSM ftpRestOrList;
 static FTPSM ftpSendStor;
 static FTPSM ftpReadStor;
+static FTPSM ftpWriteTransferDone;
 static FTPSM ftpSendReply;
-static FTPSM ftpTryMkdir;
+static FTPSM ftpSendMkdir;
 static FTPSM ftpReadMkdir;
+static FTPSM ftpFail;
+static FTPSM ftpSendQuit;
+static FTPSM ftpReadQuit;
 /************************************************
 ** State Machine Description (excluding hacks) **
 *************************************************
@@ -222,17 +221,21 @@ User                      Pass
 Pass                   Type
 Type                   TraverseDirectory / GetFile
 TraverseDirectory      Cwd / GetFile / ListDir
-Cwd                    TraverseDirectory
+Cwd                    TraverseDirectory / Mkdir
 GetFile                        Mdtm
 Mdtm                   Size
 Size                   Pasv
 ListDir                        Pasv
-Pasv                   RestOrList
-RestOrList             Rest / Retr / Nlst / List
+Pasv                   FileOrList
+FileOrList             Rest / Retr / Nlst / List / Mkdir (PUT /xxx;type=d)
 Rest                   Retr
-Retr / Nlst / List     (ftpDataRead on datachannel)
-(ftpDataRead)          ReadTransferDone
+Retr / Nlst / List     DataRead* (on datachannel)
+DataRead*              ReadTransferDone
 ReadTransferDone       DataTransferDone
+Stor                   DataWrite* (on datachannel)
+DataWrite*             RequestPutBody** (from client)
+RequestPutBody**       DataWrite* / WriteTransferDone
+WriteTransferDone      DataTransferDone
 DataTransferDone       Quit
 Quit                   -
 ************************************************/
@@ -255,7 +258,8 @@ FTPSM *FTP_SM_FUNCS[] =
     ftpReadStor,               /* SENT_STOR */
     ftpReadQuit,               /* SENT_QUIT */
     ftpReadTransferDone,       /* READING_DATA (RETR,LIST,NLST) */
-    ftpSendReply,              /* WRITING_DATA (STOR) */
+    ftpWriteTransferDone,      /* WRITING_DATA (STOR) */
+    ftpSendReply,              /* WRITTEN_DATA? (STOR) */
     ftpReadMkdir               /* SENT_MKDIR */
 };
 
@@ -838,10 +842,10 @@ ftpParseListing(FtpStateData * ftpState)
 }
 
 static void
-ftpReadComplete(FtpStateData * ftpState)
+ftpDataComplete(FtpStateData * ftpState)
 {
-    debug(9, 3) ("ftpReadComplete\n");
-    /* Connection closed; retrieval done. */
+    debug(9, 3) ("ftpDataComplete\n");
+    /* Connection closed; transfer done. */
     if (ftpState->data.fd > -1) {
        /*
         * close data socket so it does not occupy resources while
@@ -862,9 +866,9 @@ ftpDataRead(int fd, void *data)
     int j;
     int bin;
     StoreEntry *entry = ftpState->entry;
-    MemObject *mem = entry->mem_obj;
     size_t read_sz;
 #if DELAY_POOLS
+    MemObject *mem = entry->mem_obj;
     delay_id delay_id = delayMostBytesAllowed(mem);
 #endif
     assert(fd == ftpState->data.fd);
@@ -913,7 +917,7 @@ ftpDataRead(int fd, void *data)
            return;
        }
     } else if (len == 0) {
-       ftpReadComplete(ftpState);
+       ftpDataComplete(ftpState);
     } else {
        if (ftpState->flags.isdir) {
            ftpParseListing(ftpState);
@@ -921,14 +925,11 @@ ftpDataRead(int fd, void *data)
            storeAppend(entry, ftpState->data.buf, len);
            ftpState->data.offset = 0;
        }
-       if (ftpState->size > 0 && mem->inmem_hi >= ftpState->size + mem->reply->hdr_sz)
-           ftpReadComplete(ftpState);
-       else
-           commSetSelect(fd,
-               COMM_SELECT_READ,
-               ftpDataRead,
-               data,
-               Config.Timeout.read);
+       commSetSelect(fd,
+           COMM_SELECT_READ,
+           ftpDataRead,
+           data,
+           Config.Timeout.read);
     }
 }
 
@@ -1134,7 +1135,7 @@ ftpWriteCommandCallback(int fd, char *bufnotused, size_t size, int errflag, void
     if (errflag == COMM_ERR_CLOSING)
        return;
     if (errflag) {
-       debug(50, 1) ("ftpWriteCommandCallback: FD %d: %s\n", fd, xstrerror());
+       debug(9, 1) ("ftpWriteCommandCallback: FD %d: %s\n", fd, xstrerror());
        ftpFailed(ftpState, ERR_WRITE_ERROR);
        /* ftpFailed closes ctrl.fd and frees ftpState */
        return;
@@ -1528,15 +1529,15 @@ ftpReadCwd(FtpStateData * ftpState)
        if (!ftpState->flags.put)
            ftpFail(ftpState);
        else
-           ftpTryMkdir(ftpState);
+           ftpSendMkdir(ftpState);
     }
 }
 
 static void
-ftpTryMkdir(FtpStateData * ftpState)
+ftpSendMkdir(FtpStateData * ftpState)
 {
     char *path = ftpState->filepath;
-    debug(9, 3) ("ftpTryMkdir: with path=%s\n", path);
+    debug(9, 3) ("ftpSendMkdir: with path=%s\n", path);
     snprintf(cbuf, 1024, "MKD %s\r\n", path);
     ftpWriteCommand(cbuf, ftpState);
     ftpState->state = SENT_MKDIR;
@@ -1910,14 +1911,17 @@ static void
 ftpRestOrList(FtpStateData * ftpState)
 {
     debug(9, 3) ("This is ftpRestOrList\n");
-    if (ftpState->flags.put) {
-       debug(9, 3) ("ftpRestOrList: Sending STOR request...\n");
-       ftpSendStor(ftpState);
-    } else if (ftpState->typecode == 'D') {
-       /* XXX This should NOT be here */
-       ftpSendNlst(ftpState);  /* sec 3.2.2 of RFC 1738 */
+    if (ftpState->typecode == 'D') {
        ftpState->flags.isdir = 1;
        ftpState->flags.use_base = 1;
+       if (ftpState->flags.put) {
+           ftpSendMkdir(ftpState);     /* PUT name;type=d */
+       } else {
+           ftpSendNlst(ftpState);      /* GET name;type=d  sec 3.2.2 of RFC 1738 */
+       }
+    } else if (ftpState->flags.put) {
+       debug(9, 3) ("ftpRestOrList: Sending STOR request...\n");
+       ftpSendStor(ftpState);
     } else if (ftpState->flags.isdir)
        ftpSendList(ftpState);
     else if (ftpRestartable(ftpState))
@@ -1953,14 +1957,20 @@ ftpReadStor(FtpStateData * ftpState)
     if (code == 125 || (code == 150 && ftpState->data.host)) {
        /* Begin data transfer */
        debug(9, 3) ("ftpReadStor: starting data transfer\n");
+       commSetSelect(ftpState->data.fd,
+           COMM_SELECT_WRITE,
+           ftpDataWrite,
+           ftpState,
+           Config.Timeout.read);
        /*
-        * Cancel the timeout on the Control socket, pumpStart will
+        * Cancel the timeout on the Control socket and
         * establish one on the data socket.
         */
        commSetTimeout(ftpState->ctrl.fd, -1, NULL, NULL);
-       ftpPutStart(ftpState);
-       debug(9, 3) ("ftpReadStor: writing data channel\n");
+       commSetTimeout(ftpState->data.fd, Config.Timeout.read, ftpTimeout,
+           ftpState);
        ftpState->state = WRITING_DATA;
+       debug(9, 3) ("ftpReadStor: writing data channel\n");
     } else if (code == 150) {
        /* Accept data channel */
        debug(9, 3) ("ftpReadStor: accepting data channel\n");
@@ -2157,11 +2167,7 @@ ftpReadTransferDone(FtpStateData * ftpState)
        /* Connection closed; retrieval done. */
        if (ftpState->flags.html_header_sent)
            ftpListingFinish(ftpState);
-       if (!ftpState->flags.put) {
-           storeTimestampsSet(ftpState->entry);
-           fwdComplete(ftpState->fwd);
-       }
-       ftpDataTransferDone(ftpState);
+       ftpSendQuit(ftpState);
     } else {                   /* != 226 */
        debug(9, 1) ("ftpReadTransferDone: Got code %d after reading data\n",
            code);
@@ -2171,15 +2177,62 @@ ftpReadTransferDone(FtpStateData * ftpState)
     }
 }
 
+/* This will be called when there is data available to put */
 static void
-ftpDataTransferDone(FtpStateData * ftpState)
+ftpRequestBody(char *buf, size_t size, void *data)
 {
-    debug(9, 3) ("This is ftpDataTransferDone\n");
-    if (ftpState->data.fd > -1) {
-       comm_close(ftpState->data.fd);
-       ftpState->data.fd = -1;
+    FtpStateData *ftpState = (FtpStateData *) data;
+    debug(9, 3) ("ftpRequestBody: buf=%p size=%d ftpState=%p\n", buf, size, data);
+    ftpState->data.offset = size;
+    if (size > 0) {
+       /* DataWrite */
+       comm_write(ftpState->data.fd, buf, size, ftpDataWriteCallback, data, NULL);
+    } else if (size < 0) {
+       /* Error */
+       debug(9, 1) ("ftpRequestBody: request aborted");
+       ftpFailed(ftpState, ERR_READ_ERROR);
+    } else if (size == 0) {
+       /* End of transfer */
+       ftpDataComplete(ftpState);
+    }
+}
+
+/* This will be called when the put write is completed */
+static void
+ftpDataWriteCallback(int fd, char *buf, size_t size, int err, void *data)
+{
+    FtpStateData *ftpState = (FtpStateData *) data;
+    if (!err) {
+       /* Shedule the rest of the request */
+       clientReadBody(ftpState->request, ftpState->data.buf, ftpState->data.size, ftpRequestBody, ftpState);
+    } else {
+       debug(9, 1) ("ftpDataWriteCallback: write error: %s\n", xstrerror());
+       ftpFailed(ftpState, ERR_WRITE_ERROR);
     }
-    ftpSendQuit(ftpState);
+}
+
+static void
+ftpDataWrite(int ftp, void *data)
+{
+    FtpStateData *ftpState = (FtpStateData *) data;
+    debug(9, 3) ("ftpDataWrite\n");
+    /* This starts the body transfer */
+    clientReadBody(ftpState->request, ftpState->data.buf, ftpState->data.size, ftpRequestBody, ftpState);
+}
+
+static void
+ftpWriteTransferDone(FtpStateData * ftpState)
+{
+    int code = ftpState->ctrl.replycode;
+    debug(9, 3) ("This is ftpWriteTransferDone\n");
+    if (code != 226) {
+       debug(9, 1) ("ftpReadTransferDone: Got code %d after sending data\n",
+           code);
+       ftpFailed(ftpState, ERR_FTP_PUT_ERROR);
+       return;
+    }
+    storeTimestampsSet(ftpState->entry);       /* XXX Is this needed? */
+    ftpSendReply(ftpState);
 }
 
 static void
@@ -2370,48 +2423,6 @@ ftpFailedErrorMessage(FtpStateData * ftpState, err_type error)
     fwdFail(ftpState->fwd, err);
 }
 
-static void
-ftpPumpClosedData(int data_fd, void *data)
-{
-    FtpStateData *ftpState = data;
-    assert(data_fd == ftpState->data.fd);
-    /*
-     * Ugly pump module closed our server-side.  Deal with it.
-     * The data FD is already closed, so just set it to -1.
-     */
-    ftpState->data.fd = -1;
-    /*
-     * Currently, thats all we have to do.  Because the upload failed,
-     * storeAbort() will be called on the reply entry.  That will
-     * call fwdAbort, which closes ftpState->ctrl.fd and then
-     * ftpStateFree gets called.
-     */
-}
-
-static void
-ftpPutStart(FtpStateData * ftpState)
-{
-    debug(9, 3) ("ftpPutStart\n");
-    /*
-     * sigh, we need this gross hack to detect when ugly pump module
-     * aborts and wants to close the server-side.
-     */
-    comm_add_close_handler(ftpState->data.fd, ftpPumpClosedData, ftpState);
-    pumpStart(ftpState->data.fd, ftpState->fwd, ftpPutTransferDone, ftpState);
-}
-
-static void
-ftpPutTransferDone(int fd, char *bufnotused, size_t size, int errflag, void *data)
-{
-    FtpStateData *ftpState = data;
-    if (ftpState->data.fd >= 0) {
-       comm_remove_close_handler(fd, ftpPumpClosedData, ftpState);
-       comm_close(ftpState->data.fd);
-       ftpState->data.fd = -1;
-    }
-    ftpReadComplete(ftpState);
-}
-
 static void
 ftpSendReply(FtpStateData * ftpState)
 {
index 81414376de5e0846db303b23d61a20a9d548ebcc..7f4d419dc2d36fe4ed77d5f2294de30c3e4bea3b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: globals.h,v 1.99 2000/12/09 01:47:18 wessels Exp $
+ * $Id: globals.h,v 1.100 2001/01/07 23:36:39 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -145,6 +145,7 @@ extern int refresh_nocache_hack;    /* 0 */
 extern request_flags null_request_flags;
 extern int store_open_disk_fd; /* 0 */
 extern const char *SwapDirType[];
+extern authscheme_entry_t *authscheme_list;    /* NULL */
 extern storefs_entry_t *storefs_list;  /* NULL */
 extern storerepl_entry_t *storerepl_list;      /* NULL */
 extern int store_swap_low;     /* 0 */
@@ -152,3 +153,4 @@ extern int store_swap_high; /* 0 */
 extern int store_pages_max;    /* 0 */
 extern ssize_t store_maxobjsize;       /* -1 */
 extern RemovalPolicy *mem_policy;
+extern hash_table *proxy_auth_username_cache;  /* NULL */
index dd5b0e3d15f91e192f739b3b326b86bdc474f628..0201482d158f7e81fc6f612972f0fd44260d0b57 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: helper.cc,v 1.21 2001/01/05 09:51:38 adrian Exp $
+ * $Id: helper.cc,v 1.22 2001/01/07 23:36:39 hno Exp $
  *
  * DEBUG: section 29    Helper process maintenance
  * AUTHOR: Harvest Derived?
 #define HELPER_MAX_ARGS 64
 
 static PF helperHandleRead;
+static PF helperStatefulHandleRead;
 static PF helperServerFree;
+static PF helperStatefulServerFree;
 static void Enqueue(helper * hlp, helper_request *);
 static helper_request *Dequeue(helper * hlp);
+static helper_stateful_request *StatefulDequeue(statefulhelper * hlp);
 static helper_server *GetFirstAvailable(helper * hlp);
+static helper_stateful_server *StatefulGetFirstAvailable(statefulhelper * hlp);
 static void helperDispatch(helper_server * srv, helper_request * r);
+static void helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r);
 static void helperKickQueue(helper * hlp);
+static void helperStatefulKickQueue(statefulhelper * hlp);
 static void helperRequestFree(helper_request * r);
-
+static void helperStatefulRequestFree(helper_stateful_request * r);
+static void StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r);
+static helper_stateful_request *StatefulServerDequeue(helper_stateful_server * srv);
+static void StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r);
+static void helperStatefulServerKickQueue(helper_stateful_server * srv);
 
 void
 helperOpenServers(helper * hlp)
@@ -123,6 +133,87 @@ helperOpenServers(helper * hlp)
     helperKickQueue(hlp);
 }
 
+void
+helperStatefulOpenServers(statefulhelper * hlp)
+{
+    char *s;
+    char *progname;
+    char *shortname;
+    char *procname;
+    char *args[HELPER_MAX_ARGS];
+    char fd_note_buf[FD_DESC_SZ];
+    helper_stateful_server *srv;
+    int nargs = 0;
+    int k;
+    int x;
+    int rfd;
+    int wfd;
+    wordlist *w;
+    if (hlp->cmdline == NULL)
+       return;
+    progname = hlp->cmdline->key;
+    if ((s = strrchr(progname, '/')))
+       shortname = xstrdup(s + 1);
+    else
+       shortname = xstrdup(progname);
+    debug(29, 1) ("helperStatefulOpenServers: Starting %d '%s' processes\n",
+       hlp->n_to_start, shortname);
+    procname = xmalloc(strlen(shortname) + 3);
+    snprintf(procname, strlen(shortname) + 3, "(%s)", shortname);
+    args[nargs++] = procname;
+    for (w = hlp->cmdline->next; w && nargs < HELPER_MAX_ARGS; w = w->next)
+       args[nargs++] = w->key;
+    args[nargs++] = NULL;
+    assert(nargs <= HELPER_MAX_ARGS);
+    for (k = 0; k < hlp->n_to_start; k++) {
+       getCurrentTime();
+       rfd = wfd = -1;
+       x = ipcCreate(hlp->ipc_type,
+           progname,
+           args,
+           shortname,
+           &rfd,
+           &wfd);
+       if (x < 0) {
+           debug(29, 1) ("WARNING: Cannot run '%s' process.\n", progname);
+           continue;
+       }
+       hlp->n_running++;
+       srv = CBDATA_ALLOC(helper_stateful_server, NULL);
+       srv->flags.alive = 1;
+       srv->flags.reserved = S_HELPER_FREE;
+       srv->deferred_requests = 0;
+       srv->index = k;
+       srv->rfd = rfd;
+       srv->wfd = wfd;
+       srv->buf = memAllocate(MEM_8K_BUF);
+       srv->buf_sz = 8192;
+       srv->offset = 0;
+       srv->parent = hlp;
+       if (hlp->datapool != NULL)
+           srv->data = memPoolAlloc(hlp->datapool);
+       cbdataLock(hlp);        /* lock because of the parent backlink */
+       dlinkAddTail(srv, &srv->link, &hlp->servers);
+       if (rfd == wfd) {
+           snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
+           fd_note(rfd, fd_note_buf);
+       } else {
+           snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
+           fd_note(rfd, fd_note_buf);
+           snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
+           fd_note(wfd, fd_note_buf);
+       }
+       commSetNonBlocking(rfd);
+       if (wfd != rfd)
+           commSetNonBlocking(wfd);
+       comm_add_close_handler(rfd, helperStatefulServerFree, srv);
+    }
+    safe_free(shortname);
+    safe_free(procname);
+    helperStatefulKickQueue(hlp);
+}
+
+
 void
 helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data)
 {
@@ -141,6 +232,136 @@ helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data)
        helperDispatch(srv, r);
     else
        Enqueue(hlp, r);
+    debug(29, 9) ("helperSubmit: %s\n", buf);
+}
+
+void
+helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver)
+{
+    helper_stateful_request *r = memAllocate(MEM_HELPER_STATEFUL_REQUEST);
+    helper_stateful_server *srv;
+    if (hlp == NULL) {
+       debug(29, 3) ("helperStatefulSubmit: hlp == NULL\n");
+       callback(data, 0, NULL);
+       return;
+    }
+    r->callback = callback;
+    r->data = data;
+    if (buf != NULL)
+       r->buf = xstrdup(buf);
+    else
+       r->placeholder = 1;
+    cbdataLock(r->data);
+    if ((buf != NULL) && lastserver) {
+       debug(29, 5) ("StatefulSubmit with lastserver %d\n", lastserver);
+       if (lastserver->flags.reserved != S_HELPER_RESERVED)
+           lastserver->deferred_requests--;
+       if (!(lastserver->request)) {
+           debug(29, 5) ("StatefulSubmit dispatching\n");
+           helperStatefulDispatch(lastserver, r);
+       } else {
+           debug(29, 5) ("StatefulSubmit queuing\n");
+           StatefulServerEnqueue(lastserver, r);
+       }
+    } else {
+       if ((srv = StatefulGetFirstAvailable(hlp))) {
+           helperStatefulDispatch(srv, r);
+       } else
+           StatefulEnqueue(hlp, r);
+    }
+    debug(29, 9) ("helperStatefulSubmit: placeholder: '%d', buf '%s'.\n", r->placeholder, buf);
+}
+
+helper_stateful_server *
+helperStatefulDefer(statefulhelper * hlp)
+/* find and add a deferred request to a server */
+{
+    dlink_node *n;
+    helper_stateful_server *srv = NULL, *rv = NULL;
+    if (hlp == NULL) {
+       debug(29, 3) ("helperStatefulReserve: hlp == NULL\n");
+       return NULL;
+    }
+    debug(29, 5) ("helperStatefulDefer: Running servers %d.\n", hlp->n_running);
+    if (hlp->n_running == 0) {
+       debug(29, 1) ("helperStatefulDefer: No running servers!. \n");
+       return NULL;
+    }
+    srv = StatefulGetFirstAvailable(hlp);
+    /* all currently busy:loop through servers and find server with the shortest queue */
+    rv = srv;
+    if (rv == NULL)
+       for (n = hlp->servers.head; n != NULL; n = n->next) {
+           srv = n->data;
+           if (srv->flags.reserved == S_HELPER_RESERVED)
+               continue;
+           if (!srv->flags.alive)
+               continue;
+           if ((hlp->IsAvailable != NULL) && (srv->data != NULL) &&
+               !(hlp->IsAvailable(srv->data)))
+               continue;
+           if ((rv != NULL) && (rv->deferred_requests < srv->deferred_requests))
+               continue;
+           rv = srv;
+       }
+    if (rv == NULL) {
+       debug(29, 1) ("helperStatefulDefer: None available.\n");
+       return NULL;
+    }
+    rv->flags.reserved = S_HELPER_DEFERRED;
+    rv->deferred_requests++;
+    return rv;
+}
+
+void
+helperStatefulReset(helper_stateful_server * srv)
+/* puts this helper back in the queue. the calling app is required to 
+ * manage the state in the helper.
+ */
+{
+    statefulhelper *hlp = srv->parent;
+    helper_stateful_request *r;
+    r = srv->request;
+    if (r != NULL) {
+       /* reset attempt DURING an outstaning request */
+       debug(29, 1) ("helperStatefulReset: RESET During request %s \n",
+           hlp->id_name);
+       srv->flags.busy = 0;
+       srv->offset = 0;
+       helperStatefulRequestFree(r);
+       srv->request = NULL;
+    }
+    debug(29, 1) ("helperStatefulReset reset helper %s #%d\n", hlp->id_name, srv->index + 1);
+    srv->flags.busy = 0;
+    if (srv->queue.head) {
+       srv->flags.reserved = S_HELPER_DEFERRED;
+       helperStatefulServerKickQueue(srv);
+    } else {
+       srv->flags.reserved = S_HELPER_FREE;
+       if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
+           srv->parent->OnEmptyQueue(srv->data);
+       helperStatefulKickQueue(hlp);
+    }
+}
+
+void
+helperStatefulReleaseServer(helper_stateful_server * srv)
+/*decrease the number of 'waiting' clients that set the helper to be DEFERRED */
+{
+    if (srv->deferred_requests > 0)
+       srv->deferred_requests--;
+    if (!(srv->deferred_requests) && (srv->flags.reserved == S_HELPER_DEFERRED) && !(srv->queue.head)) {
+       srv->flags.reserved = S_HELPER_FREE;
+       if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
+           srv->parent->OnEmptyQueue(srv->data);
+    }
+}
+
+void *
+helperStatefulServerGetData(helper_stateful_server * srv)
+/* return a pointer to the stateful routines data area */
+{
+    return srv->data;
 }
 
 void
@@ -190,6 +411,57 @@ helperStats(StoreEntry * sentry, helper * hlp)
     storeAppendPrintf(sentry, "   S = SHUTDOWN\n");
 }
 
+void
+helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp)
+{
+    helper_stateful_server *srv;
+    dlink_node *link;
+    double tt;
+    storeAppendPrintf(sentry, "number running: %d of %d\n",
+       hlp->n_running, hlp->n_to_start);
+    storeAppendPrintf(sentry, "requests sent: %d\n",
+       hlp->stats.requests);
+    storeAppendPrintf(sentry, "replies received: %d\n",
+       hlp->stats.replies);
+    storeAppendPrintf(sentry, "queue length: %d\n",
+       hlp->stats.queue_size);
+    storeAppendPrintf(sentry, "avg service time: %d msec\n",
+       hlp->stats.avg_svc_time);
+    storeAppendPrintf(sentry, "\n");
+    storeAppendPrintf(sentry, "%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\n",
+       "#",
+       "FD",
+       "# Requests",
+       "# Deferred Requests",
+       "Flags",
+       "Time",
+       "Offset",
+       "Request");
+    for (link = hlp->servers.head; link; link = link->next) {
+       srv = link->data;
+       tt = 0.001 * tvSubMsec(srv->dispatch_time, current_time);
+       storeAppendPrintf(sentry, "%7d\t%7d\t%11d\t%11d\t%c%c%c%c%c\t%7.3f\t%7d\t%s\n",
+           srv->index + 1,
+           srv->rfd,
+           srv->stats.uses,
+           srv->deferred_requests,
+           srv->flags.alive ? 'A' : ' ',
+           srv->flags.busy ? 'B' : ' ',
+           srv->flags.closing ? 'C' : ' ',
+           srv->flags.reserved != S_HELPER_FREE ? 'R' : ' ',
+           srv->flags.shutdown ? 'S' : ' ',
+           tt < 0.0 ? 0.0 : tt,
+           (int) srv->offset,
+           srv->request ? log_quote(srv->request->buf) : "(none)");
+    }
+    storeAppendPrintf(sentry, "\nFlags key:\n\n");
+    storeAppendPrintf(sentry, "   A = ALIVE\n");
+    storeAppendPrintf(sentry, "   B = BUSY\n");
+    storeAppendPrintf(sentry, "   C = CLOSING\n");
+    storeAppendPrintf(sentry, "   R = RESERVED or DEFERRED\n");
+    storeAppendPrintf(sentry, "   S = SHUTDOWN\n");
+}
+
 void
 helperShutdown(helper * hlp)
 {
@@ -220,6 +492,47 @@ helperShutdown(helper * hlp)
     }
 }
 
+void
+helperStatefulShutdown(statefulhelper * hlp)
+{
+    dlink_node *link = hlp->servers.head;
+    helper_stateful_server *srv;
+    while (link) {
+       srv = link->data;
+       link = link->next;
+       if (!srv->flags.alive) {
+           debug(34, 3) ("helperStatefulShutdown: %s #%d is NOT ALIVE.\n",
+               hlp->id_name, srv->index + 1);
+           continue;
+       }
+       srv->flags.shutdown = 1;        /* request it to shut itself down */
+       if (srv->flags.busy) {
+           debug(34, 3) ("helperStatefulShutdown: %s #%d is BUSY.\n",
+               hlp->id_name, srv->index + 1);
+           continue;
+       }
+       if (srv->flags.closing) {
+           debug(34, 3) ("helperStatefulShutdown: %s #%d is CLOSING.\n",
+               hlp->id_name, srv->index + 1);
+           continue;
+       }
+       if (srv->flags.reserved != S_HELPER_FREE) {
+           debug(34, 3) ("helperStatefulShutdown: %s #%d is RESERVED.\n",
+               hlp->id_name, srv->index + 1);
+           continue;
+       }
+       if (srv->deferred_requests) {
+           debug(34, 3) ("helperStatefulShutdown: %s #%d has DEFERRED requests.\n",
+               hlp->id_name, srv->index + 1);
+           continue;
+       }
+       srv->flags.closing = 1;
+       comm_close(srv->wfd);
+       srv->wfd = -1;
+    }
+}
+
+
 helper *
 helperCreate(const char *name)
 {
@@ -229,6 +542,16 @@ helperCreate(const char *name)
     return hlp;
 }
 
+statefulhelper *
+helperStatefulCreate(const char *name)
+{
+    statefulhelper *hlp;
+    hlp = CBDATA_ALLOC(statefulhelper, NULL);
+    hlp->id_name = name;
+    return hlp;
+}
+
+
 void
 helperFree(helper * hlp)
 {
@@ -239,6 +562,17 @@ helperFree(helper * hlp)
     cbdataFree(hlp);
 }
 
+void
+helperStatefulFree(statefulhelper * hlp)
+{
+    /* note, don't free hlp->name, it probably points to static memory */
+    if (hlp->queue.head)
+       debug(29, 0) ("WARNING: freeing %s helper with %d requests queued\n",
+           hlp->id_name, hlp->stats.queue_size);
+    cbdataFree(hlp);
+}
+
+
 /* ====================================================================== */
 /* LOCAL FUNCTIONS */
 /* ====================================================================== */
@@ -275,6 +609,41 @@ helperServerFree(int fd, void *data)
     cbdataFree(srv);
 }
 
+static void
+helperStatefulServerFree(int fd, void *data)
+{
+    helper_stateful_server *srv = data;
+    statefulhelper *hlp = srv->parent;
+    helper_stateful_request *r;
+    assert(srv->rfd == fd);
+    if (srv->buf) {
+       memFree(srv->buf, MEM_8K_BUF);
+       srv->buf = NULL;
+    }
+    if ((r = srv->request)) {
+       if (cbdataValid(r->data))
+           r->callback(r->data, srv, srv->buf);
+       helperStatefulRequestFree(r);
+       srv->request = NULL;
+    }
+    if (srv->wfd != srv->rfd && srv->wfd != -1)
+       comm_close(srv->wfd);
+    dlinkDelete(&srv->link, &hlp->servers);
+    hlp->n_running--;
+    assert(hlp->n_running >= 0);
+    if (!srv->flags.shutdown) {
+       debug(34, 0) ("WARNING: %s #%d (FD %d) exited\n",
+           hlp->id_name, srv->index + 1, fd);
+       if (hlp->n_running < hlp->n_to_start / 2)
+           fatalf("Too few %s processes are running", hlp->id_name);
+    }
+    if (srv->data != NULL)
+       memPoolFree(hlp->datapool, srv->data);
+    cbdataUnlock(srv->parent);
+    cbdataFree(srv);
+}
+
+
 static void
 helperHandleRead(int fd, void *data)
 {
@@ -329,6 +698,101 @@ helperHandleRead(int fd, void *data)
     }
 }
 
+static void
+helperStatefulHandleRead(int fd, void *data)
+{
+    int len;
+    char *t = NULL;
+    helper_stateful_server *srv = data;
+    helper_stateful_request *r;
+    statefulhelper *hlp = srv->parent;
+    assert(fd == srv->rfd);
+    assert(cbdataValid(data));
+    statCounter.syscalls.sock.reads++;
+    len = read(fd, srv->buf + srv->offset, srv->buf_sz - srv->offset);
+    fd_bytes(fd, len, FD_READ);
+    debug(29, 5) ("helperStatefulHandleRead: %d bytes from %s #%d.\n",
+       len, hlp->id_name, srv->index + 1);
+    if (len <= 0) {
+       if (len < 0)
+           debug(50, 1) ("helperStatefulHandleRead: FD %d read: %s\n", fd, xstrerror());
+       comm_close(fd);
+       return;
+    }
+    srv->offset += len;
+    srv->buf[srv->offset] = '\0';
+    r = srv->request;
+    if (r == NULL) {
+       /* someone spoke without being spoken to */
+       debug(29, 1) ("helperStatefulHandleRead: unexpected read from %s #%d, %d bytes\n",
+           hlp->id_name, srv->index + 1, len);
+       srv->offset = 0;
+    } else if ((t = strchr(srv->buf, '\n'))) {
+       /* end of reply found */
+       debug(29, 3) ("helperStatefulHandleRead: end of reply found\n");
+       *t = '\0';
+       if (cbdataValid(r->data)) {
+           switch ((r->callback(r->data, srv, srv->buf))) {    /*if non-zero reserve helper */
+           case S_HELPER_UNKNOWN:
+               fatal("helperStatefulHandleRead: either a non-state aware callback was give to the stateful helper routines, or an uninitialised callback response was recieved.\n");
+               break;
+           case S_HELPER_RELEASE:      /* helper finished with */
+               if (!srv->queue.head) {
+                   srv->flags.reserved = S_HELPER_FREE;
+                   if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
+                       srv->parent->OnEmptyQueue(srv->data);
+                   debug(29, 5) ("StatefulHandleRead: releasing %s #%d\n", hlp->id_name, srv->index + 1);
+               } else {
+                   srv->flags.reserved = S_HELPER_DEFERRED;
+                   debug(29, 5) ("StatefulHandleRead: outstanding deferred requests on %s #%d. reserving for deferred requests.\n", hlp->id_name, srv->index + 1);
+               }
+               break;
+           case S_HELPER_RESERVE:      /* 'pin' this helper for the caller */
+               if (!srv->queue.head) {
+                   srv->flags.reserved = S_HELPER_RESERVED;
+                   debug(29, 5) ("StatefulHandleRead: reserving %s #%d\n", hlp->id_name, srv->index + 1);
+               } else {
+                   fatal("StatefulHandleRead: Callback routine attempted to reserve a stateful helper with deferred requests. This can lead to deadlock.\n");
+               }
+               break;
+           case S_HELPER_DEFER:
+               /* the helper is still needed, but can
+                * be used for other requests in the meantime.
+                */
+               srv->flags.reserved = S_HELPER_DEFERRED;
+               srv->deferred_requests++;
+               debug(29, 5) ("StatefulHandleRead: reserving %s #%d for deferred requests.\n", hlp->id_name, srv->index + 1);
+               break;
+           default:
+               fatal("helperStatefulHandleRead: unknown stateful helper callback result.\n");
+           }
+
+       } else {
+           debug(29, 1) ("StatefulHandleRead: no callback data registered\n");
+       }
+       srv->flags.busy = 0;
+       srv->offset = 0;
+       helperStatefulRequestFree(r);
+       srv->request = NULL;
+       hlp->stats.replies++;
+       hlp->stats.avg_svc_time =
+           intAverage(hlp->stats.avg_svc_time,
+           tvSubMsec(srv->dispatch_time, current_time),
+           hlp->stats.replies, REDIRECT_AV_FACTOR);
+       if (srv->flags.shutdown) {
+           comm_close(srv->wfd);
+           srv->wfd = -1;
+       } else {
+           if (srv->queue.head)
+               helperStatefulServerKickQueue(srv);
+           else
+               helperStatefulKickQueue(hlp);
+       }
+    } else {
+       commSetSelect(srv->rfd, COMM_SELECT_READ, helperStatefulHandleRead, srv, 0);
+    }
+}
+
 static void
 Enqueue(helper * hlp, helper_request * r)
 {
@@ -349,6 +813,35 @@ Enqueue(helper * hlp, helper_request * r)
     debug(14, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
 }
 
+static void
+StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r)
+{
+    dlink_node *link = memAllocate(MEM_DLINK_NODE);
+    dlinkAddTail(r, link, &hlp->queue);
+    hlp->stats.queue_size++;
+    if (hlp->stats.queue_size < hlp->n_running)
+       return;
+    if (squid_curtime - hlp->last_queue_warn < 600)
+       return;
+    if (shutting_down || reconfiguring)
+       return;
+    hlp->last_queue_warn = squid_curtime;
+    debug(14, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
+    debug(14, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
+    if (hlp->stats.queue_size > hlp->n_running * 2)
+       fatalf("Too many queued %s requests", hlp->id_name);
+    debug(14, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
+}
+
+static void
+StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r)
+{
+    dlink_node *link = memAllocate(MEM_DLINK_NODE);
+    dlinkAddTail(r, link, &srv->queue);
+    /* XXX No queue length check here? */
+}
+
+
 static helper_request *
 Dequeue(helper * hlp)
 {
@@ -363,6 +856,33 @@ Dequeue(helper * hlp)
     return r;
 }
 
+static helper_stateful_request *
+StatefulServerDequeue(helper_stateful_server * srv)
+{
+    dlink_node *link;
+    helper_stateful_request *r = NULL;
+    if ((link = srv->queue.head)) {
+       r = link->data;
+       dlinkDelete(link, &srv->queue);
+       memFree(link, MEM_DLINK_NODE);
+    }
+    return r;
+}
+
+static helper_stateful_request *
+StatefulDequeue(statefulhelper * hlp)
+{
+    dlink_node *link;
+    helper_stateful_request *r = NULL;
+    if ((link = hlp->queue.head)) {
+       r = link->data;
+       dlinkDelete(link, &hlp->queue);
+       memFree(link, MEM_DLINK_NODE);
+       hlp->stats.queue_size--;
+    }
+    return r;
+}
+
 static helper_server *
 GetFirstAvailable(helper * hlp)
 {
@@ -381,6 +901,31 @@ GetFirstAvailable(helper * hlp)
     return NULL;
 }
 
+static helper_stateful_server *
+StatefulGetFirstAvailable(statefulhelper * hlp)
+{
+    dlink_node *n;
+    helper_stateful_server *srv = NULL;
+    debug(29, 5) ("StatefulGetFirstAvailable: Running servers %d.\n", hlp->n_running);
+    if (hlp->n_running == 0)
+       return NULL;
+    for (n = hlp->servers.head; n != NULL; n = n->next) {
+       srv = n->data;
+       if (srv->flags.busy)
+           continue;
+       if (srv->flags.reserved == S_HELPER_RESERVED)
+           continue;
+       if (!srv->flags.alive)
+           continue;
+       if ((hlp->IsAvailable != NULL) && (srv->data != NULL) && !(hlp->IsAvailable(srv->data)))
+           continue;
+       return srv;
+    }
+    debug(29, 5) ("StatefulGetFirstAvailable: None available.\n");
+    return NULL;
+}
+
+
 static void
 helperDispatch(helper_server * srv, helper_request * r)
 {
@@ -410,6 +955,60 @@ helperDispatch(helper_server * srv, helper_request * r)
     hlp->stats.requests++;
 }
 
+static void
+helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r)
+{
+    statefulhelper *hlp = srv->parent;
+    if (!cbdataValid(r->data)) {
+       debug(29, 1) ("helperStatefulDispatch: invalid callback data\n");
+       helperStatefulRequestFree(r);
+       return;
+    }
+    debug(29, 9) ("helperStatefulDispatch busying helper %s #%d\n", hlp->id_name, srv->index + 1);
+    if (r->placeholder == 1) {
+       /* a callback is needed before this request can _use_ a helper. */
+       if (cbdataValid(r->data)) {
+           /* we don't care about releasing/deferring this helper. The request NEVER
+            * gets to the helper. So we throw away the return code */
+           r->callback(r->data, srv, NULL);
+           /* throw away the placeholder */
+           helperStatefulRequestFree(r);
+           /* and push the queue. Note that the callback may have call submit again - 
+            * which is why we test for the request*/
+           if (srv->request == NULL) {
+               if (srv->flags.shutdown) {
+                   comm_close(srv->wfd);
+                   srv->wfd = -1;
+               } else {
+                   if (srv->queue.head)
+                       helperStatefulServerKickQueue(srv);
+                   else
+                       helperStatefulKickQueue(hlp);
+               }
+           }
+       }
+       return;
+    }
+    srv->flags.busy = 1;
+    srv->request = r;
+    srv->dispatch_time = current_time;
+    comm_write(srv->wfd,
+       r->buf,
+       strlen(r->buf),
+       NULL,                   /* Handler */
+       NULL,                   /* Handler-data */
+       NULL);                  /* free */
+    commSetSelect(srv->rfd,
+       COMM_SELECT_READ,
+       helperStatefulHandleRead,
+       srv, 0);
+    debug(29, 5) ("helperStatefulDispatch: Request sent to %s #%d, %d bytes\n",
+       hlp->id_name, srv->index + 1, strlen(r->buf));
+    srv->stats.uses++;
+    hlp->stats.requests++;
+}
+
+
 static void
 helperKickQueue(helper * hlp)
 {
@@ -419,6 +1018,23 @@ helperKickQueue(helper * hlp)
        helperDispatch(srv, r);
 }
 
+static void
+helperStatefulKickQueue(statefulhelper * hlp)
+{
+    helper_stateful_request *r;
+    helper_stateful_server *srv;
+    while ((srv = StatefulGetFirstAvailable(hlp)) && (r = StatefulDequeue(hlp)))
+       helperStatefulDispatch(srv, r);
+}
+
+static void
+helperStatefulServerKickQueue(helper_stateful_server * srv)
+{
+    helper_stateful_request *r;
+    if ((r = StatefulServerDequeue(srv)))
+       helperStatefulDispatch(srv, r);
+}
+
 static void
 helperRequestFree(helper_request * r)
 {
@@ -426,3 +1042,11 @@ helperRequestFree(helper_request * r)
     xfree(r->buf);
     memFree(r, MEM_HELPER_REQUEST);
 }
+
+static void
+helperStatefulRequestFree(helper_stateful_request * r)
+{
+    cbdataUnlock(r->data);
+    xfree(r->buf);
+    memFree(r, MEM_HELPER_STATEFUL_REQUEST);
+}
index 34439d91701e0fd0572012c444aead01a19b26bb..a8e63eb3057f9d814cb5b57c8eb9d55bce18eec0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.cc,v 1.374 2001/01/05 09:51:38 adrian Exp $
+ * $Id: http.cc,v 1.375 2001/01/07 23:36:39 hno Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -44,7 +44,6 @@ static const char *const crlf = "\r\n";
 
 static CWCB httpSendComplete;
 static CWCB httpSendRequestEntry;
-static CWCB httpSendRequestEntryDone;
 
 static PF httpReadReply;
 static void httpSendRequest(HttpStateData *);
@@ -690,16 +689,27 @@ httpBuildRequestHeader(request_t * request,
        }
        switch (e->id) {
        case HDR_PROXY_AUTHORIZATION:
-           /* If we're not doing proxy auth, then it must be passed on */
-           if (!request->flags.used_proxy_auth)
+           /* Only pass on proxy authentication to peers for which
+            * authentication forwarding is explicitly enabled
+            */
+           if (request->flags.proxying && orig_request->peer_login &&
+               strcmp(orig_request->peer_login, "PASS") == 0) {
                httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+           }
            break;
        case HDR_AUTHORIZATION:
-           /* If we're not doing www auth, then it must be passed on */
-           if (!request->flags.accelerated || !request->flags.used_proxy_auth)
-               httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
-           else
-               request->flags.auth = 0;        /* We have used the authentication */
+           /* Pass on WWW authentication even if used locally. If this is
+            * not wanted in an accelerator then the header can be removed
+            * using the anonymization functions
+            */
+           httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+           /* XXX Some accelerators might want to strip the header
+            * and regard the reply as cacheable, but authentication
+            * is not normally enabled for accelerators without reading
+            * the code, so there is not much use in adding logics here
+            * without first defining the concept of having authentication
+            * in the accelerator...
+            */
            break;
        case HDR_HOST:
            /*
@@ -780,7 +790,8 @@ httpBuildRequestHeader(request_t * request,
     }
     /* append Proxy-Authorization if configured for peer, and proxying */
     if (!httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION)) {
-       if (request->flags.proxying && orig_request->peer_login) {
+       if (request->flags.proxying && orig_request->peer_login &&
+           strcmp(orig_request->peer_login, "PASS") != 0) {
            httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
                base64_encode(orig_request->peer_login));
        }
@@ -855,7 +866,7 @@ httpSendRequest(HttpStateData * httpState)
 
     debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState);
 
-    if (httpState->orig_request->content_length > 0)
+    if (httpState->orig_request->body_connection)
        sendHeaderDone = httpSendRequestEntry;
     else
        sendHeaderDone = httpSendComplete;
@@ -869,6 +880,8 @@ httpSendRequest(HttpStateData * httpState)
     assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type);
     if (p != NULL)
        httpState->flags.proxying = 1;
+    else
+       httpState->flags.proxying = 0;
     /*
      * Is keep-alive okay for all request methods?
      */
@@ -953,43 +966,50 @@ httpStart(FwdState * fwd)
 }
 
 static void
-httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data)
+httpSendRequestEntryDone(int fd, void *data)
 {
     HttpStateData *httpState = data;
-    StoreEntry *entry = httpState->entry;
-    ErrorState *err;
-    debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n",
-       fd, size, errflag);
-    if (size > 0) {
-       fd_bytes(fd, size, FD_WRITE);
-       kb_incr(&statCounter.server.all.kbytes_out, size);
-       kb_incr(&statCounter.server.http.kbytes_out, size);
-    }
-    if (errflag == COMM_ERR_CLOSING)
-       return;
-    if (errflag) {
-       err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
-       err->xerrno = errno;
-       err->request = requestLink(httpState->orig_request);
-       errorAppendEntry(entry, err);
-       comm_close(fd);
-       return;
+    aclCheck_t ch;
+    debug(11, 5) ("httpSendRequestEntryDone: FD %d\n",
+       fd);
+    memset(&ch, '\0', sizeof(ch));
+    ch.request = httpState->request;
+    if (!Config.accessList.brokenPosts) {
+       debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n");
+       httpSendComplete(fd, NULL, 0, 0, data);
+    } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
+       debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n");
+       httpSendComplete(fd, NULL, 0, 0, data);
+    } else {
+       debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n");
+       comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
     }
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-       comm_close(fd);
-       return;
+}
+
+static void
+httpRequestBodyHandler(char *buf, size_t size, void *data)
+{
+    HttpStateData *httpState = (HttpStateData *) data;
+    if (size > 0) {
+       comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K);
+    } else if (size == 0) {
+       /* End of body */
+       memFree8K(buf);
+       httpSendRequestEntryDone(httpState->fd, data);
+    } else {
+       /* Failed to get whole body, probably aborted */
+       memFree8K(buf);
+       httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
     }
-    pumpStart(fd, httpState->fwd, httpSendRequestEntryDone, httpState);
 }
 
 static void
-httpSendRequestEntryDone(int fd, char *bufnotused, size_t size, int errflag, void *data)
+httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data)
 {
     HttpStateData *httpState = data;
     StoreEntry *entry = httpState->entry;
     ErrorState *err;
-    aclCheck_t ch;
-    debug(11, 5) ("httpSendRequestEntryDone: FD %d: size %d: errflag %d.\n",
+    debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n",
        fd, size, errflag);
     if (size > 0) {
        fd_bytes(fd, size, FD_WRITE);
@@ -1006,18 +1026,11 @@ httpSendRequestEntryDone(int fd, char *bufnotused, size_t size, int errflag, voi
        comm_close(fd);
        return;
     }
-    memset(&ch, '\0', sizeof(ch));
-    ch.request = httpState->request;
-    if (!Config.accessList.brokenPosts) {
-       debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n");
-       httpSendComplete(fd, NULL, 0, 0, data);
-    } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
-       debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n");
-       httpSendComplete(fd, NULL, 0, 0, data);
-    } else {
-       debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n");
-       comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
+    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+       comm_close(fd);
+       return;
     }
+    clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
 }
 
 void
index 556516d9634fd1179632628c5eaae06013eb629e..e5c05b2c6534d1999ee8084b9bca7ac54f38dd26 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.328 2001/01/05 09:51:39 adrian Exp $
+ * $Id: main.cc,v 1.329 2001/01/07 23:36:39 hno Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -349,6 +349,7 @@ mainReconfigure(void)
     parseConfigFile(ConfigFile);
     _db_init(Config.Log.log, Config.debugOptions);
     ipcache_restart();         /* clear stuck entries */
+    authenticateUserCacheRestart();    /* clear stuck ACL entries */
     fqdncache_restart();       /* sigh, fqdncache too */
     parseEtcHosts();
     errorInitialize();         /* reload error pages */
@@ -358,7 +359,7 @@ mainReconfigure(void)
     idnsInit();
 #endif
     redirectInit();
-    authenticateInit();
+    authenticateInit(&Config.authConfig);
 #if USE_WCCP
     wccpInit();
 #endif
@@ -399,7 +400,7 @@ mainRotate(void)
     dnsInit();
 #endif
     redirectInit();
-    authenticateInit();
+    authenticateInit(&Config.authConfig);
 }
 
 static void
@@ -489,7 +490,7 @@ mainInitialize(void)
     idnsInit();
 #endif
     redirectInit();
-    authenticateInit();
+    authenticateInit(&Config.authConfig);
     useragentOpenLog();
     refererOpenLog();
     httpHeaderInitModule();    /* must go before any header processing (e.g. the one in errorInitialize) */
@@ -632,6 +633,7 @@ main(int argc, char **argv)
        cbdataInit();
        eventInit();            /* eventInit() is required for config parsing */
        storeFsInit();          /* required for config parsing */
+       authenticateSchemeInit();       /* required for config parsign */
        parse_err = parseConfigFile(ConfigFile);
 
        if (opt_parse_cfg_only)
index 52692e60186a6e582081d3d20ba8bbe5bd6ba133..24fad0f5b74636689df4b2333db42fa25b9514ee 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: mem.cc,v 1.52 2001/01/07 20:11:18 hno Exp $
+ * $Id: mem.cc,v 1.53 2001/01/07 23:36:39 hno Exp $
  *
  * DEBUG: section 13    High Level Memory Pool Management
  * AUTHOR: Harvest Derived
@@ -204,10 +204,14 @@ memInit(void)
     memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0);
     memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
     memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
+    memDataInit(MEM_AUTH_USER_T, "auth_user_t",
+       sizeof(auth_user_t), 0);
+    memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer",
+       sizeof(auth_user_hash_pointer), 0);
+    memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache",
+       sizeof(acl_proxy_auth_match_cache), 0);
     memDataInit(MEM_ACL_USER_DATA, "acl_user_data",
        sizeof(acl_user_data), 0);
-    memDataInit(MEM_ACL_PROXY_AUTH_USER, "acl_proxy_auth_user",
-       sizeof(acl_proxy_auth_user), 0);
     memDataInit(MEM_CACHEMGR_PASSWD, "cachemgr_passwd",
        sizeof(cachemgr_passwd), 0);
 #if USE_CACHE_DIGESTS
@@ -286,10 +290,15 @@ memInit(void)
     memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0);
     memDataInit(MEM_MD5_DIGEST, "MD5 digest", MD5_DIGEST_CHARS, 0);
     memDataInit(MEM_HELPER, "helper", sizeof(helper), 0);
+    memDataInit(MEM_HELPER_STATEFUL, "stateful_helper", sizeof(statefulhelper), 0);
     memDataInit(MEM_HELPER_REQUEST, "helper_request",
        sizeof(helper_request), 0);
+    memDataInit(MEM_HELPER_STATEFUL_REQUEST, "helper_stateful_request",
+       sizeof(helper_stateful_request), 0);
     memDataInit(MEM_HELPER_SERVER, "helper_server",
        sizeof(helper_server), 0);
+    memDataInit(MEM_HELPER_STATEFUL_SERVER, "helper_stateful_server",
+       sizeof(helper_stateful_server), 0);
     memDataInit(MEM_STORE_IO, "storeIOState", sizeof(storeIOState), 0);
     memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
     memDataInit(MEM_GEN_CBDATA, "generic_cbdata", sizeof(generic_cbdata), 0);
index d85bec4da19ff4b5d24eb7fc7e095453693dcbbb..c393371026d315388a532408cf87b1f1244f5edc 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.392 2001/01/05 09:51:39 adrian Exp $
+ * $Id: protos.h,v 1.393 2001/01/07 23:36:39 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -46,6 +46,7 @@ extern void headersLog(int cs, int pq, method_t m, void *data);
 #endif
 char *log_quote(const char *header);
 
+/* acl.c */
 extern aclCheck_t *aclChecklistCreate(const struct _acl_access *,
     request_t *,
     const char *ident);
@@ -67,6 +68,7 @@ extern void aclParseRegexList(void *curlist);
 extern const char *aclTypeToStr(squid_acl);
 extern wordlist *aclDumpGeneric(const acl *);
 extern int aclPurgeMethodInUse(acl_access *);
+extern void aclCacheMatchFlush(dlink_list * cache);
 
 /*
  * cache_cf.c
@@ -85,6 +87,12 @@ extern void allocate_new_swapdir(cacheSwap *);
 extern void self_destruct(void);
 extern int GetInteger(void);
 
+/* extra functions from cache_cf.c useful for lib modules */
+extern void parse_int(int *var);
+extern void parse_eol(char *volatile *var);
+extern void parse_wordlist(wordlist ** list);
+extern void requirePathnameExists(const char *name, const char *path);
+extern void parse_time_t(time_t * var);
 
 /*
  * cbdata.c
@@ -123,6 +131,8 @@ extern void clientHttpConnectionsOpen(void);
 extern void clientHttpConnectionsClose(void);
 extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
 extern int isTcpHit(log_type);
+extern void clientReadBody(request_t * req, char *buf, size_t size, CBCB * callback, void *data);
+extern int clientAbortBody(request_t * req);
 
 extern int commSetNonBlocking(int fd);
 extern int commUnsetNonBlocking(int fd);
@@ -707,9 +717,47 @@ extern void redirectStart(clientHttpRequest *, RH *, void *);
 extern void redirectInit(void);
 extern void redirectShutdown(void);
 
-extern void authenticateStart(acl_proxy_auth_user *, RH *, void *);
-extern void authenticateInit(void);
+/* auth_modules.c */
+extern void authSchemeSetup(void);
+
+/* authenticate.c */
+extern void authenticateAuthUserMerge(auth_user_t *, auth_user_t *);
+extern auth_user_t *authenticateAuthUserNew(const char *);
+extern int authenticateAuthSchemeId(const char *typestr);
+extern void authenticateStart(auth_user_request_t *, RH *, void *);
+extern void authenticateSchemeInit(void);
+extern void authenticateInit(authConfig *);
 extern void authenticateShutdown(void);
+extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int);
+extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int);
+extern auth_user_request_t *authenticateGetAuthUser(const char *proxy_auth);
+extern void authenticateAuthenticateUser(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type);
+extern void authenticateAuthUserUnlock(auth_user_t * auth_user);
+extern void authenticateAuthUserLock(auth_user_t * auth_user);
+extern void authenticateAuthUserRequestUnlock(auth_user_request_t *);
+extern void authenticateAuthUserRequestLock(auth_user_request_t *);
+extern char *authenticateAuthUserRequestMessage(auth_user_request_t *);
+extern int authenticateAuthUserInuse(auth_user_t * auth_user);
+extern void authenticateAuthUserRequestSetIp(auth_user_request_t *, struct in_addr);
+extern int authenticateDirection(auth_user_request_t *);
+extern FREE authenticateFreeProxyAuthUser;
+extern void authenticateFreeProxyAuthUserACLResults(void *data);
+extern void authenticateProxyUserCacheCleanup(void *);
+extern void authenticateInitUserCache();
+#if 0
+extern void authenticateProxyAuthCacheAddLink(const char *key, auth_user_t *);
+#endif
+extern int authenticateActiveSchemeCount();
+extern int authenticateSchemeCount();
+extern void authenticateUserNameCacheAdd(auth_user_t * auth_user);
+extern int authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user);
+extern int authenticateUserAuthenticated(auth_user_request_t *);
+extern void authenticateUserCacheRestart();
+extern char *authenticateUserUsername(auth_user_t *);
+extern char *authenticateUserRequestUsername(auth_user_request_t *);
+extern int authenticateValidateUser(auth_user_request_t *);
+extern void authenticateOnCloseConnection(ConnStateData * conn);
+extern void authSchemeAdd(char *type, AUTHSSETUP * setup);
 
 extern void refreshAddToList(const char *, int, time_t, int, time_t);
 extern int refreshIsCachable(const StoreEntry *);
@@ -1028,11 +1076,6 @@ extern void releaseServerSockets(void);
 extern void PrintRusage(void);
 extern void dumpMallocStats(void);
 
-extern void pumpInit(int fd, request_t * r, char *uri);
-extern void pumpStart(int, FwdState *, CWCB * callback, void *);
-extern int pumpMethod(method_t method);
-extern int pumpRestart(request_t *);
-
 #if USE_UNLINKD
 extern void unlinkdInit(void);
 extern void unlinkdClose(void);
@@ -1084,6 +1127,9 @@ extern void asnFreeMemory(void);
 extern void dlinkAdd(void *data, dlink_node *, dlink_list *);
 extern void dlinkAddTail(void *data, dlink_node *, dlink_list *);
 extern void dlinkDelete(dlink_node * m, dlink_list * list);
+extern void dlinkNodeDelete(dlink_node * m);
+extern dlink_node *dlinkNodeNew();
+
 extern void kb_incr(kb_t *, size_t);
 extern double gb_to_double(const gb_t *);
 extern const char *gb_to_str(const gb_t *);
@@ -1187,11 +1233,23 @@ extern void delayUnregisterDelayIdPtr(delay_id * loc);
 
 /* helper.c */
 extern void helperOpenServers(helper * hlp);
+extern void helperStatefulOpenServers(statefulhelper * hlp);
 extern void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data);
+extern void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver);
 extern void helperStats(StoreEntry * sentry, helper * hlp);
+extern void helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp);
 extern void helperShutdown(helper * hlp);
+extern void helperStatefulShutdown(statefulhelper * hlp);
 extern helper *helperCreate(const char *);
+extern statefulhelper *helperStatefulCreate(const char *);
 extern void helperFree(helper *);
+extern void helperStatefulFree(statefulhelper *);
+extern void helperStatefulReset(helper_stateful_server * srv);
+extern void helperStatefulReleaseServer(helper_stateful_server * srv);
+extern void *helperStatefulServerGetData(helper_stateful_server * srv);
+extern helper_stateful_server *helperStatefulDefer(statefulhelper *);
+
+
 
 #if USE_LEAKFINDER
 extern void leakInit(void);
index e7391726fbb92ce723c6401963357a303c52e02c..9d4705329017246a67ffe77febd7faf514712ab0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: redirect.cc,v 1.85 2001/01/05 09:51:40 adrian Exp $
+ * $Id: redirect.cc,v 1.86 2001/01/07 23:36:40 hno Exp $
  *
  * DEBUG: section 29    Redirector
  * AUTHOR: Duane Wessels
@@ -126,12 +126,12 @@ redirectStart(clientHttpRequest * http, RH * handler, void *data)
     r = CBDATA_ALLOC(redirectStateData, NULL);
     r->orig_url = xstrdup(http->uri);
     r->client_addr = conn->log_addr;
-    if (http->request->user_ident[0])
-       r->client_ident = http->request->user_ident;
-    else if (conn->ident == NULL || *conn->ident == '\0') {
-       r->client_ident = dash_str;
+    if (http->request->auth_user_request)
+       r->client_ident = authenticateUserRequestUsername(http->request->auth_user_request);
+    else if (conn->rfc931[0]) {
+       r->client_ident = conn->rfc931;
     } else {
-       r->client_ident = conn->ident;
+       r->client_ident = dash_str;
     }
     r->method_s = RequestMethodStr[http->request->method];
     r->handler = handler;
index f7f56bc41d9b69d57f8caf8280c6edb39e445a28..4d11b7f6e2496f560de5a162567fa123c7be50b9 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ssl.cc,v 1.109 2001/01/05 09:51:40 adrian Exp $
+ * $Id: ssl.cc,v 1.110 2001/01/07 23:36:40 hno Exp $
  *
  * DEBUG: section 26    Secure Sockets Layer Proxy
  * AUTHOR: Duane Wessels
@@ -587,6 +587,7 @@ sslPeerSelectComplete(FwdServer * fs, void *data)
        sslState->request->peer_login = fs->peer->login;
        sslState->request->flags.proxying = 1;
     } else {
+       sslState->request->peer_login = NULL;
        sslState->request->flags.proxying = 0;
     }
 #if DELAY_POOLS
index 428c665905c8aa3c3219d92318f5ede5f2b73df0..74219a0803052ce1bc86e91c4fc4238573fc048b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: stat.cc,v 1.341 2001/01/05 09:51:40 adrian Exp $
+ * $Id: stat.cc,v 1.342 2001/01/07 23:36:40 hno Exp $
  *
  * DEBUG: section 18    Cache Manager Statistics
  * AUTHOR: Harvest Derived
@@ -1415,8 +1415,6 @@ statClientRequests(StoreEntry * s)
                ntohs(conn->me.sin_port));
            storeAppendPrintf(s, "\tnrequests: %d\n",
                conn->nrequests);
-           storeAppendPrintf(s, "\tpersistent: %d\n",
-               conn->persistent);
            storeAppendPrintf(s, "\tdefer: n %d, until %d\n",
                conn->defer.n, conn->defer.until);
        }
index 7e3e74caeebaf91348e69870a9513eb25526edcd..0e5d77caef0236fe2aeebbbf94dd38edca49ad82 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.374 2001/01/07 19:55:20 hno Exp $
+ * $Id: structs.h,v 1.375 2001/01/07 23:36:40 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -73,15 +73,100 @@ struct _acl_name_list {
     acl_name_list *next;
 };
 
-struct _acl_proxy_auth_user {
-    hash_link hash;            /* must be first */
+struct _acl_proxy_auth_match_cache {
+    dlink_node link;
+    int matchrv;
+    void *acl_data;
+};
+
+struct _auth_user_hash_pointer {
+    /* first two items must be same as hash_link */
+    char *key;
+    auth_user_hash_pointer *next;
+    auth_user_t *auth_user;
+    dlink_node link;           /* other hash entries that point to the same auth_user */
+};
+
+struct _auth_user_t {
     /* extra fields for proxy_auth */
-    char *passwd;
-    int passwd_ok;             /* 1 = passwd checked OK */
+    /* this determines what scheme owns the user data. */
+    auth_type_t auth_type;
+    /* the index +1 in the authscheme_list to the authscheme entry */
+    int auth_module;
+    /* we only have one username associated with a given auth_user struct */
+    auth_user_hash_pointer *usernamehash;
+    /* we may have many proxy-authenticate strings that decode to the same user */
+    dlink_list proxy_auth_list;
+    dlink_list proxy_match_cache;
+    struct {
+       unsigned int credentials_ok:2;  /*0=unchecked,1=ok,2=failed */
+    } flags;
     long expiretime;
-    struct in_addr ipaddr;     /* IP addr this user authenticated from */
+    /* IP addr this user authenticated from */
+    struct in_addr ipaddr;
     time_t ip_expiretime;
+    /* how many references are outstanding to this instance */
+    size_t references;
+    /* the auth scheme has it's own private data area */
+    void *scheme_data;
+    /* the auth_user_request structures that link to this. Yes it could be a splaytree
+     * but how many requests will a single username have in parallel? */
+    dlink_list requests;
+};
+
+struct _auth_user_request_t {
+    /* this is the object passed around by client_side and acl functions */
+    /* it has request specific data, and links to user specific data */
+    /* the user */
+    auth_user_t *auth_user;
+    /* return a message on the 407 error pages */
     char *message;
+    /* any scheme specific request related data */
+    void *scheme_data;
+    /* how many 'processes' are working on this data */
+    size_t references;
+};
+
+
+/*
+ * This defines an auth scheme module
+ */
+
+struct _authscheme_entry {
+    char *typestr;
+    AUTHSACTIVE *Active;
+    AUTHSADDHEADER *AddHeader;
+    AUTHSADDTRAILER *AddTrailer;
+    AUTHSAUTHED *authenticated;
+    AUTHSAUTHUSER *authAuthenticate;
+    AUTHSDUMP *dump;
+    AUTHSFIXERR *authFixHeader;
+    AUTHSFREE *FreeUser;
+    AUTHSFREECONFIG *freeconfig;
+    AUTHSUSERNAME *authUserUsername;
+    AUTHSONCLOSEC *oncloseconnection;  /*optional */
+    AUTHSDECODE *decodeauth;
+    AUTHSDIRECTION *getdirection;
+    AUTHSPARSE *parse;
+    AUTHSINIT *init;
+    AUTHSREQFREE *requestFree;
+    AUTHSSHUTDOWN *donefunc;
+    AUTHSSTART *authStart;
+    AUTHSSTATS *authStats;
+};
+
+/*
+ * This is a configured auth scheme
+ */
+
+/* private data types */
+struct _authScheme {
+    /* pointer to the authscheme_list's string entry */
+    char *typestr;
+    /* the scheme id in the authscheme_list */
+    int Id;
+    /* the scheme's configuration details. */
+    void *scheme_data;
 };
 
 struct _acl_deny_info_list {
@@ -161,11 +246,9 @@ struct _aclCheck_t {
     struct in_addr my_addr;
     unsigned short my_port;
     request_t *request;
-#if USE_IDENT
-    ConnStateData *conn;       /* hack for ident */
-    char ident[USER_IDENT_SZ];
-#endif
-    acl_proxy_auth_user *auth_user;
+    ConnStateData *conn;       /* hack for ident and NTLM */
+    char rfc931[USER_IDENT_SZ];
+    auth_user_request_t *auth_user_request;
     acl_lookup_state state[ACL_ENUM_MAX];
 #if SQUID_SNMP
     char *snmp_community;
@@ -206,6 +289,7 @@ struct _sockaddr_in_list {
     sockaddr_in_list *next;
 };
 
+
 #if DELAY_POOLS
 struct _delaySpec {
     int restore_bps;
@@ -334,7 +418,6 @@ struct _SquidConfig {
        char *dnsserver;
 #endif
        wordlist *redirect;
-       wordlist *authenticate;
 #if USE_ICMP
        char *pinger;
 #endif
@@ -346,7 +429,7 @@ struct _SquidConfig {
     int dnsChildren;
 #endif
     int redirectChildren;
-    int authenticateChildren;
+    time_t authenticateGCInterval;
     time_t authenticateTTL;
     time_t authenticateIpTTL;
     struct {
@@ -470,7 +553,11 @@ struct _SquidConfig {
        acl_access *redirector;
     } accessList;
     acl_deny_info_list *denyInfoList;
-    char *proxyAuthRealm;
+    struct _authConfig {
+       authScheme *schemes;
+       int n_allocated;
+       int n_configured;
+    } authConfig;
     struct {
        size_t list_width;
        int list_wrap;
@@ -876,7 +963,8 @@ struct _AccessLogEntry {
        size_t size;
        log_type code;
        int msec;
-       const char *ident;
+       const char *rfc931;
+       const char *authuser;
     } cache;
     struct {
        char *request;
@@ -932,13 +1020,25 @@ struct _ConnStateData {
        off_t offset;
        size_t size;
     } in;
+    struct {
+       size_t size_left;       /* How much body left to process */
+       request_t *request;     /* Parameters passed to clientReadBody */
+       char *buf;
+       size_t bufsize;
+       CBCB *callback;
+       void *cbdata;
+    } body;
+    auth_type_t auth_type;     /* Is this connection based authentication ? if so 
+                                * what type it is. */
+    /* note this is ONLY connection based because NTLM is against HTTP spec */
+    /* the user details for connection based authentication */
+    auth_user_request_t *auth_user_request;
     clientHttpRequest *chr;
     struct sockaddr_in peer;
     struct sockaddr_in me;
     struct in_addr log_addr;
-    char ident[USER_IDENT_SZ];
+    char rfc931[USER_IDENT_SZ];
     int nrequests;
-    int persistent;
     struct {
        int n;
        time_t until;
@@ -1421,7 +1521,6 @@ struct _request_flags {
     unsigned int proxy_keepalive:1;
     unsigned int proxying:1;
     unsigned int refresh:1;
-    unsigned int used_proxy_auth:1;
     unsigned int redirected:1;
     unsigned int need_validation:1;
 #if HTTP_VIOLATIONS
@@ -1429,6 +1528,7 @@ struct _request_flags {
 #endif
     unsigned int accelerated:1;
     unsigned int internal:1;
+    unsigned int body_sent:1;
 };
 
 struct _link_list {
@@ -1461,7 +1561,7 @@ struct _request_t {
     protocol_t protocol;
     char login[MAX_LOGIN_SZ];
     char host[SQUIDHOSTNAMELEN + 1];
-    char user_ident[USER_IDENT_SZ];    /* from proxy auth or ident server */
+    auth_user_request_t *auth_user_request;
     u_short port;
     String urlpath;
     char *canonical;
@@ -1478,8 +1578,7 @@ struct _request_t {
     struct in_addr my_addr;
     unsigned short my_port;
     HttpHeader header;
-    char *body;
-    size_t body_sz;
+    ConnStateData *body_connection;    /* used by clientReadBody() */
     int content_length;
     HierarchyLogEntry hier;
     err_type err_type;
@@ -1524,13 +1623,13 @@ struct _ErrorState {
     err_type type;
     int page_id;
     http_status http_status;
+    auth_user_request_t *auth_user_request;
     request_t *request;
     char *url;
     int xerrno;
     char *host;
     u_short port;
     char *dnsserver_msg;
-    char *proxy_auth_msg;
     time_t ttl;
     struct in_addr src_addr;
     char *redirect_url;
@@ -1816,6 +1915,15 @@ struct _helper_request {
     void *data;
 };
 
+struct _helper_stateful_request {
+    char *buf;
+    HLPSCB *callback;
+    int placeholder;           /* if 1, this is a dummy request waiting for a stateful helper
+                                * to become available for deferred requests.*/
+    void *data;
+};
+
+
 struct _helper {
     wordlist *cmdline;
     dlink_list servers;
@@ -1833,6 +1941,26 @@ struct _helper {
     } stats;
 };
 
+struct _helper_stateful {
+    wordlist *cmdline;
+    dlink_list servers;
+    dlink_list queue;
+    const char *id_name;
+    int n_to_start;
+    int n_running;
+    int ipc_type;
+    MemPool *datapool;
+    HLPSAVAIL *IsAvailable;
+    HLPSONEQ *OnEmptyQueue;
+    time_t last_queue_warn;
+    struct {
+       int requests;
+       int replies;
+       int queue_size;
+       int avg_svc_time;
+    } stats;
+};
+
 struct _helper_server {
     int index;
     int rfd;
@@ -1856,6 +1984,34 @@ struct _helper_server {
     } stats;
 };
 
+
+struct _helper_stateful_server {
+    int index;
+    int rfd;
+    int wfd;
+    char *buf;
+    size_t buf_sz;
+    off_t offset;
+    struct timeval dispatch_time;
+    struct timeval answer_time;
+    dlink_node link;
+    dlink_list queue;
+    statefulhelper *parent;
+    helper_stateful_request *request;
+    struct _helper_stateful_flags {
+       unsigned int alive:1;
+       unsigned int busy:1;
+       unsigned int closing:1;
+       unsigned int shutdown:1;
+       stateful_helper_reserve_t reserved:2;
+    } flags;
+    struct {
+       int uses;
+    } stats;
+    size_t deferred_requests;  /* current number of deferred requests */
+    void *data;                        /* State data used by the calling routines */
+};
+
 /*
  * use this when you need to pass callback data to a blocking
  * operation, but you don't want to add that pointer to cbdata
index f08689b333531ef380568f3b565d76ea810efcb2..645163dd7d535b3d2ecfee31790a501c7930b5e1 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: tools.cc,v 1.202 2001/01/04 03:42:35 wessels Exp $
+ * $Id: tools.cc,v 1.203 2001/01/07 23:36:40 hno Exp $
  *
  * DEBUG: section 21    Misc Functions
  * AUTHOR: Harvest Derived
@@ -62,6 +62,8 @@ extern int setresuid(uid_t, uid_t, uid_t);
 
 extern void (*failure_notify) (const char *);
 
+MemPool *dlink_node_pool = NULL;
+
 void
 releaseServerSockets(void)
 {
@@ -762,6 +764,24 @@ checkNullString(char *p)
     return p ? p : "(NULL)";
 }
 
+dlink_node *
+dlinkNodeNew()
+{
+    if (dlink_node_pool == NULL)
+       dlink_node_pool = memPoolCreate("Dlink list nodes", sizeof(dlink_node));
+    /* where should we call memPoolDestroy(dlink_node_pool); */
+    return memPoolAlloc(dlink_node_pool);
+}
+
+/* the node needs to be unlinked FIRST */
+void
+dlinkNodeDelete(dlink_node * m)
+{
+    if (m == NULL)
+       return;
+    memPoolFree(dlink_node_pool, m);
+}
+
 void
 dlinkAdd(void *data, dlink_node * m, dlink_list * list)
 {
index 581f7d6c343a80d4285bd6209e8538f282bb02c1..55f6f83511bfd52748112e7745cdda08468bc06a 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: tunnel.cc,v 1.109 2001/01/05 09:51:40 adrian Exp $
+ * $Id: tunnel.cc,v 1.110 2001/01/07 23:36:40 hno Exp $
  *
  * DEBUG: section 26    Secure Sockets Layer Proxy
  * AUTHOR: Duane Wessels
@@ -587,6 +587,7 @@ sslPeerSelectComplete(FwdServer * fs, void *data)
        sslState->request->peer_login = fs->peer->login;
        sslState->request->flags.proxying = 1;
     } else {
+       sslState->request->peer_login = NULL;
        sslState->request->flags.proxying = 0;
     }
 #if DELAY_POOLS
index 8eed27c0ca791e0f1972990471746eb8e9747338..f28297ed7d7f5c897f420feaff9eeef6062a4627 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.115 2001/01/07 19:55:20 hno Exp $
+ * $Id: typedefs.h,v 1.116 2001/01/07 23:36:41 hno Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -61,8 +61,14 @@ typedef struct _acl_ip_data acl_ip_data;
 typedef struct _acl_time_data acl_time_data;
 typedef struct _acl_name_list acl_name_list;
 typedef struct _acl_deny_info_list acl_deny_info_list;
+typedef struct _acl_proxy_auth acl_proxy_auth;
+typedef struct _auth_user_t auth_user_t;
+typedef struct _auth_user_request_t auth_user_request_t;
+typedef struct _auth_user_hash_pointer auth_user_hash_pointer;
+typedef struct _acl_proxy_auth_match_cache acl_proxy_auth_match_cache;
+typedef struct _authscheme_entry authscheme_entry_t;
+typedef struct _authScheme authScheme;
 typedef struct _acl_user_data acl_user_data;
-typedef struct _acl_proxy_auth_user acl_proxy_auth_user;
 typedef struct _acl_arp_data acl_arp_data;
 typedef struct _acl acl;
 typedef struct _acl_snmp_comm acl_snmp_comm;
@@ -105,6 +111,7 @@ typedef struct _HttpStateData HttpStateData;
 typedef struct _icpUdpData icpUdpData;
 typedef struct _clientHttpRequest clientHttpRequest;
 typedef struct _ConnStateData ConnStateData;
+typedef struct _ConnCloseHelperData ConnCloseHelperData;
 typedef struct _ipcache_addrs ipcache_addrs;
 typedef struct _domain_ping domain_ping;
 typedef struct _domain_type domain_type;
@@ -134,6 +141,7 @@ typedef struct _StoreEntry StoreEntry;
 typedef struct _SwapDir SwapDir;
 typedef struct _request_flags request_flags;
 typedef struct _helper_flags helper_flags;
+typedef struct _helper_stateful_flags helper_stateful_flags;
 typedef struct _http_state_flags http_state_flags;
 typedef struct _header_mangler header_mangler;
 typedef struct _request_t request_t;
@@ -147,6 +155,7 @@ typedef struct _dlink_list dlink_list;
 typedef struct _StatCounters StatCounters;
 typedef struct _tlv tlv;
 typedef struct _storeSwapLogData storeSwapLogData;
+typedef struct _authConfig authConfig;
 typedef struct _cacheSwap cacheSwap;
 typedef struct _StatHist StatHist;
 typedef struct _String String;
@@ -160,8 +169,11 @@ typedef struct _Version Version;
 typedef struct _FwdState FwdState;
 typedef struct _FwdServer FwdServer;
 typedef struct _helper helper;
+typedef struct _helper_stateful statefulhelper;
 typedef struct _helper_server helper_server;
+typedef struct _helper_stateful_server helper_stateful_server;
 typedef struct _helper_request helper_request;
+typedef struct _helper_stateful_request helper_stateful_request;
 typedef struct _generic_cbdata generic_cbdata;
 typedef struct _storeIOState storeIOState;
 typedef struct _queued_read queued_read;
@@ -217,6 +229,7 @@ typedef void PSC(FwdServer *, void *);
 typedef void RH(void *data, char *);
 typedef void UH(void *data, wordlist *);
 typedef int DEFER(int fd, void *data);
+typedef void CBCB(char *buf, size_t size, void *data);
 
 typedef void STIOCB(void *their_data, int errflag, storeIOState *);
 typedef void STFNCB(void *their_data, int errflag, storeIOState *);
@@ -231,6 +244,9 @@ typedef void OBJH(StoreEntry *);
 typedef void SIGHDLR(int sig);
 typedef void STVLDCB(void *, int, int);
 typedef void HLPCB(void *, char *buf);
+typedef stateful_helper_callback_t HLPSCB(void *, void *lastserver, char *buf);
+typedef int HLPSAVAIL(void *);
+typedef void HLPSONEQ(void *);
 typedef void HLPCMDOPTS(int *argc, char **argv);
 typedef void IDNSCB(void *, rfc1035_rr *, int);
 
@@ -274,6 +290,28 @@ typedef void STFSSHUTDOWN(void);
 typedef double hbase_f(double);
 typedef void StatHistBinDumper(StoreEntry *, int idx, double val, double size, int count);
 
+/* authenticate.c authenticate scheme routines typedefs */
+typedef int AUTHSACTIVE();
+typedef int AUTHSAUTHED(auth_user_request_t *);
+typedef void AUTHSAUTHUSER(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type);
+typedef void AUTHSDECODE(auth_user_request_t *, const char *);
+typedef int AUTHSDIRECTION(auth_user_request_t *);
+typedef void AUTHSDUMP(StoreEntry *, const char *, authScheme *);
+typedef void AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *);
+typedef void AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int);
+typedef void AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int);
+typedef void AUTHSFREE(auth_user_t *);
+typedef void AUTHSFREECONFIG(authScheme *);
+typedef char *AUTHSUSERNAME(auth_user_t *);
+typedef void AUTHSONCLOSEC(ConnStateData *);
+typedef void AUTHSPARSE(authScheme *, int, char *);
+typedef void AUTHSINIT(authScheme *);
+typedef void AUTHSREQFREE(auth_user_request_t *);
+typedef void AUTHSSETUP(authscheme_entry_t *);
+typedef void AUTHSSHUTDOWN(void);
+typedef void AUTHSSTART(auth_user_request_t *, RH *, void *);
+typedef void AUTHSSTATS(StoreEntry *);
+
 /* append/vprintf's for Packer */
 typedef void (*append_f) (void *, const char *buf, int size);
 #if STDC_HEADERS