This patch is generated from the push branch of HEAD in squid
Mon Jan 26 12:58:16 2004 GMT
See http://devel.squid-cache.org/
Index: squid/CONTRIBUTORS
diff -u squid/CONTRIBUTORS:1.22 squid/CONTRIBUTORS:1.17.6.2
--- squid/CONTRIBUTORS:1.22 Fri Jul 5 15:42:12 2002
+++ squid/CONTRIBUTORS Tue Sep 3 10:39:07 2002
@@ -88,5 +88,6 @@
Ian Castle
- Most custom types and tools are documented in the code or the relevant
- portions of this manual. Some key points apply globally however.
-
-
- If you need to use specific width types - such as
- a 16 bit unsigned integer, use one of the following types. To access
- them simply include "config.h".
-
- These routines decide whether a cached object is stale or fresh,
+ These routines decide wether a cached object is stale or fresh,
based on the
We are experimenting with URN support in Squid version 1.2.
Note, we're not talking full-blown generic URN's here. This
- is primarily targeted toward using URN's as an smart way
+ is primarily targeted towards using URN's as an smart way
of handling lists of mirror sites. For more details, please
see
Macro that defines a new cbdata datatype. Similar to a variable
or struct definition. Scope is always local to the file/block
- where it is defined and all calls to cbdataAlloc for this type
- must be within the same scope as the CBDATA_TYPE declaration.
- Allocated entries may be referenced or freed anywhere with no
- restrictions on scope.
+ where it is defined and all allocations must be within this scope.
+ Allocated entries referenced or freed anywhere with no restrictions
+ on scope.
Removes a reference created by cbdataReference() and checks
- it for validity. A temporary pointer to the referenced data
- (if valid) is returned in the &pointer argument.
+ it for validity.
- Meant to be used on the last dereference, usually to make
- a callback.
+ Meant to be used on the last dereference
- Here you can find some examples on how to use cbdata, and why
-
-
- For a asyncronous operation with callback functions, the normal
- sequence of events in programs NOT using cbdata is as follows:
+ For a blocking operation
+ with callback functions, the normal sequence of events is as
+ follows:
The callback data allocator lets us do this in a uniform and
safe manner. The callback data allocator is used to allocate,
track and free memory pool objects used during callback
- operations. Allocated memory is locked while the asyncronous
+ operations. Allocated memory is locked while the blocking
operation executes elsewhere, and is freed when the operation
completes. The normal sequence of events is:
With this scheme, nothing bad happens if
- /* initialization */
- type_of_data our_data;
- ...
- our_data = cbdataAlloc(type_of_data);
+ callback_data = cbdataAlloc(...);
...
- /* Initiate a asyncronous operation, with our_data as callback_data */
- fooOperationStart(..., callback_func, our_data);
+ fooOperationStart(bar, callback_func, callback_data);
+ local_pointer = cbdataReference(callback_data);
...
- /* foo */
- void *local_pointer = cbdataReference(callback_data);
- ....
- /* something bad happened elsewhere.. cleanup */
- cbdataFree(our_data);
+ cbdataFree(callback_data);
...
- /* The asyncronous operation completes and tries to make the callback */
+ fooOperationComplete(...);
void *cbdata;
- if (cbdataReferenceValidDone(local_pointer, &cbdata))
- /* won't be called, as the data is no longer valid */
- callback_func(...., cbdata);
-
+ if (cbdataReferenceValidDone(local_pointer, cbdata))
+ callback_func(cbdata, ....);
- To add new global data types that can be allocated from anywhere
- within the code one have to add them to the cbdata_type enum in
- enums.h, and a corresponding CREATE_CBDATA call in
- cbdata.c:cbdataInit(). Or alternatively add a CBDATA_GLOBAL_TYPE
- definition to globals.h as shown below and use CBDATA_INIT_TYPE at
- the appropriate location(s) as described above.
+ To add new global data types one have to add them to the
+ cbdata_type enum in enums.h, and a corresponding
+ CREATE_CBDATA call in cbdata.c:cbdataInit(). Or alternatively
+ add a CBDATA_GLOBAL_TYPE definition to globals.h and use
+ CBDATA_INIT_TYPE as described above.
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+The system returned:
+
+This means that:
+
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED
diff -u squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CACHE_ACCESS_DENIED Tue Sep 3 10:39:18 2002
@@ -1,12 +1,10 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED
diff -u squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4 squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CACHE_MGR_ACCESS_DENIED Tue Sep 3 10:39:19 2002
@@ -1,12 +1,10 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_CANNOT_FORWARD
diff -u squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4 squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4.6.1
--- squid/errors/Catalan/ERR_CANNOT_FORWARD:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CANNOT_FORWARD Tue Sep 3 10:39:19 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_CONNECT_FAIL
diff -u squid/errors/Catalan/ERR_CONNECT_FAIL:1.4 squid/errors/Catalan/ERR_CONNECT_FAIL:1.4.6.1
--- squid/errors/Catalan/ERR_CONNECT_FAIL:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_CONNECT_FAIL Tue Sep 3 10:39:20 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_DNS_FAIL
diff -u squid/errors/Catalan/ERR_DNS_FAIL:1.4 squid/errors/Catalan/ERR_DNS_FAIL:1.4.6.1
--- squid/errors/Catalan/ERR_DNS_FAIL:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_DNS_FAIL Tue Sep 3 10:39:20 2002
@@ -1,10 +1,8 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_FORWARDING_DENIED
diff -u squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4 squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4.6.1
--- squid/errors/Catalan/ERR_FORWARDING_DENIED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FORWARDING_DENIED Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_FTP_DISABLED
diff -u squid/errors/Catalan/ERR_FTP_DISABLED:1.4 squid/errors/Catalan/ERR_FTP_DISABLED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_DISABLED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_DISABLED Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_FTP_FAILURE
diff -u squid/errors/Catalan/ERR_FTP_FAILURE:1.4 squid/errors/Catalan/ERR_FTP_FAILURE:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_FAILURE:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_FAILURE Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
S'ha produït un error FTP mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_FTP_FORBIDDEN
diff -u squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4 squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_FORBIDDEN:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_FORBIDDEN Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
S'ha produït un error en l'autentificació FTP
mentre s'intentava llegir la URL
Index: squid/errors/Catalan/ERR_FTP_NOT_FOUND
diff -u squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4 squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_NOT_FOUND:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_NOT_FOUND Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
URL:
%U
Index: squid/errors/Catalan/ERR_FTP_PUT_CREATED
diff -u squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4 squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_CREATED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_CREATED Tue Sep 3 10:39:21 2002
@@ -1,8 +1,6 @@
-
-
Mentre s'intentava la comanda PUT a la URL:
%U
Index: squid/errors/Catalan/ERR_FTP_PUT_MODIFIED
diff -u squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4 squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_MODIFIED:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_MODIFIED Tue Sep 3 10:39:21 2002
@@ -1,8 +1,6 @@
-
-
El servidor FTP estava massa ocupat quan intentava mostrar la URL:
%U
Index: squid/errors/Catalan/ERR_INVALID_REQ
diff -u squid/errors/Catalan/ERR_INVALID_REQ:1.4 squid/errors/Catalan/ERR_INVALID_REQ:1.4.6.1
--- squid/errors/Catalan/ERR_INVALID_REQ:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_INVALID_REQ Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_LIFETIME_EXP
diff -u squid/errors/Catalan/ERR_LIFETIME_EXP:1.4 squid/errors/Catalan/ERR_LIFETIME_EXP:1.4.6.1
--- squid/errors/Catalan/ERR_LIFETIME_EXP:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_LIFETIME_EXP Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_NO_RELAY
diff -u squid/errors/Catalan/ERR_NO_RELAY:1.4 squid/errors/Catalan/ERR_NO_RELAY:1.4.6.1
--- squid/errors/Catalan/ERR_NO_RELAY:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_NO_RELAY Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS
diff -u squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4 squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4.6.1
--- squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_ONLY_IF_CACHED_MISS Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_READ_ERROR
diff -u squid/errors/Catalan/ERR_READ_ERROR:1.4 squid/errors/Catalan/ERR_READ_ERROR:1.4.6.1
--- squid/errors/Catalan/ERR_READ_ERROR:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_READ_ERROR Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_READ_TIMEOUT
diff -u squid/errors/Catalan/ERR_READ_TIMEOUT:1.4 squid/errors/Catalan/ERR_READ_TIMEOUT:1.4.6.1
--- squid/errors/Catalan/ERR_READ_TIMEOUT:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_READ_TIMEOUT Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_SHUTTING_DOWN
diff -u squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4 squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4.6.1
--- squid/errors/Catalan/ERR_SHUTTING_DOWN:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_SHUTTING_DOWN Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_SOCKET_FAILURE
diff -u squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4 squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4.6.1
--- squid/errors/Catalan/ERR_SOCKET_FAILURE:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_SOCKET_FAILURE Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_TOO_BIG
diff -u squid/errors/Catalan/ERR_TOO_BIG:1.4 squid/errors/Catalan/ERR_TOO_BIG:1.4.6.1
--- squid/errors/Catalan/ERR_TOO_BIG:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_TOO_BIG Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_UNSUP_REQ
diff -u squid/errors/Catalan/ERR_UNSUP_REQ:1.4 squid/errors/Catalan/ERR_UNSUP_REQ:1.4.6.1
--- squid/errors/Catalan/ERR_UNSUP_REQ:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_UNSUP_REQ Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_URN_RESOLVE
diff -u squid/errors/Catalan/ERR_URN_RESOLVE:1.4 squid/errors/Catalan/ERR_URN_RESOLVE:1.4.6.1
--- squid/errors/Catalan/ERR_URN_RESOLVE:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_URN_RESOLVE Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URN:
%U
Index: squid/errors/Catalan/ERR_WRITE_ERROR
diff -u squid/errors/Catalan/ERR_WRITE_ERROR:1.5 squid/errors/Catalan/ERR_WRITE_ERROR:1.5.6.1
--- squid/errors/Catalan/ERR_WRITE_ERROR:1.5 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_WRITE_ERROR Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT
diff -u squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4 squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4.6.1
--- squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_ZERO_SIZE_OBJECT Tue Sep 3 10:39:23 2002
@@ -1,11 +1,9 @@
-
-
Mentre s'intentava llegir la URL:
%U
Index: squid/errors/Catalan/generic
diff -u squid/errors/Catalan/generic:1.2 squid/errors/Catalan/generic:1.2.10.1
--- squid/errors/Catalan/generic:1.2 Thu Jul 18 17:00:42 2002
+++ squid/errors/Catalan/generic Tue Sep 3 10:39:24 2002
@@ -1,11 +1,9 @@
-
Mentre s'intentava llegir la URL::
%U
Index: squid/errors/Czech/ERR_CONFLICT
diff -u /dev/null squid/errors/Czech/ERR_CONFLICT:1.1.2.1
--- /dev/null Mon Jan 26 04:57:35 2004
+++ squid/errors/Czech/ERR_CONFLICT Sat Dec 22 08:31:34 2001
@@ -0,0 +1,30 @@
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+This means that:
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+ %E
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
Accés denegat a la cache
-
+
ERROR
ERROR: Accés denegat a l'administració de la cache
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
Operació completada
Fitxer creat
-
+
Index: squid/errors/Catalan/ERR_FTP_PUT_ERROR
diff -u squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4 squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_PUT_ERROR:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_PUT_ERROR Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
+
ERROR
Ha fallat la comanda FTP d'enviament de fitxer
-
+
Operació completada
Fitxer actualitzat
-
+
Index: squid/errors/Catalan/ERR_FTP_UNAVAILABLE
diff -u squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4 squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4.6.1
--- squid/errors/Catalan/ERR_FTP_UNAVAILABLE:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_FTP_UNAVAILABLE Tue Sep 3 10:39:21 2002
@@ -1,11 +1,9 @@
-
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
Index: squid/errors/Catalan/ERR_INVALID_URL
diff -u squid/errors/Catalan/ERR_INVALID_URL:1.4 squid/errors/Catalan/ERR_INVALID_URL:1.4.6.1
--- squid/errors/Catalan/ERR_INVALID_URL:1.4 Wed Aug 28 14:45:33 2002
+++ squid/errors/Catalan/ERR_INVALID_URL Tue Sep 3 10:39:22 2002
@@ -1,11 +1,9 @@
-
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URN que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
No es pot mostrar la URL que heu sol.licitat
-
+
ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+ERROR
+The requested URL could not be retrieved
+
+
+
+
+
+When you make a PUT request to a cache, you must supply an object with
+a Last-Modified time at least as recent as the version the cache already
+has. Otherwise, the version you sent is considered stale and is thrown out.
+Either the cache has already received a more recent copy from elsewhere,
+or your client push software is computing Last-Modified time incorrectly.
+
+
+While trying to retrieve the URL: +%U +
+The following error was encountered: +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/German/ERR_CONFLICT diff -u /dev/null squid/errors/German/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/German/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +
+While trying to retrieve the URL: +%U +
+The following error was encountered: +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Hebrew/ERR_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ACCESS_DENIED Tue Sep 3 10:39:55 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CACHE_ACCESS_DENIED Tue Sep 3 10:39:55 2002 @@ -1,14 +1,12 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED diff -u squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3 squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CACHE_MGR_ACCESS_DENIED Tue Sep 3 10:39:56 2002 @@ -1,14 +1,12 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_CANNOT_FORWARD diff -u squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3 squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3.6.1 --- squid/errors/Hebrew/ERR_CANNOT_FORWARD:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CANNOT_FORWARD Tue Sep 3 10:39:56 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_CONNECT_FAIL diff -u squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3 squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3.6.1 --- squid/errors/Hebrew/ERR_CONNECT_FAIL:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_CONNECT_FAIL Tue Sep 3 10:39:56 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_DNS_FAIL diff -u squid/errors/Hebrew/ERR_DNS_FAIL:1.4 squid/errors/Hebrew/ERR_DNS_FAIL:1.4.6.1 --- squid/errors/Hebrew/ERR_DNS_FAIL:1.4 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_DNS_FAIL Tue Sep 3 10:39:57 2002 @@ -1,12 +1,10 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_FORWARDING_DENIED diff -u squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3 squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3.6.1 --- squid/errors/Hebrew/ERR_FORWARDING_DENIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FORWARDING_DENIED Tue Sep 3 10:39:57 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_FTP_DISABLED diff -u squid/errors/Hebrew/ERR_FTP_DISABLED:1.3 squid/errors/Hebrew/ERR_FTP_DISABLED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_DISABLED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_DISABLED Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_FTP_FAILURE diff -u squid/errors/Hebrew/ERR_FTP_FAILURE:1.3 squid/errors/Hebrew/ERR_FTP_FAILURE:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_FAILURE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_FAILURE Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
÷øúä ùâéàú ôøåèå÷åì FTP ëàùø ðéñéúé ìâùú àì äëúåáú: %U Index: squid/errors/Hebrew/ERR_FTP_FORBIDDEN diff -u squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3 squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_FORBIDDEN:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_FORBIDDEN Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä áæéäåé îùúîù FTP ëàùø ðéñéúé ìâùú àì äëúåáú: %U Index: squid/errors/Hebrew/ERR_FTP_NOT_FOUND diff -u squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3 squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_NOT_FOUND:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_NOT_FOUND Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ìà ðéúï ìâùú àì äëúåáú äð"ì: %U Index: squid/errors/Hebrew/ERR_FTP_PUT_CREATED diff -u squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_PUT_CREATED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_PUT_CREATED Tue Sep 3 10:39:59 2002 @@ -1,10 +1,8 @@ -
ùâéàä ëàùø ðéñéúé ìùìåç àú: %U Index: squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED diff -u squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3 squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3.6.1 --- squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_FTP_PUT_MODIFIED Tue Sep 3 10:39:59 2002 @@ -1,10 +1,8 @@ -
ùøú ä-FTP äéä òñå÷ îãé, ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_INVALID_REQ diff -u squid/errors/Hebrew/ERR_INVALID_REQ:1.3 squid/errors/Hebrew/ERR_INVALID_REQ:1.3.6.1 --- squid/errors/Hebrew/ERR_INVALID_REQ:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_INVALID_REQ Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ëàùø ðéñéúé ìòáã àú äá÷ùä:
Index: squid/errors/Hebrew/ERR_INVALID_URL diff -u squid/errors/Hebrew/ERR_INVALID_URL:1.3 squid/errors/Hebrew/ERR_INVALID_URL:1.3.6.1 --- squid/errors/Hebrew/ERR_INVALID_URL:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_INVALID_URL Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_LIFETIME_EXP diff -u squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3 squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3.6.1 --- squid/errors/Hebrew/ERR_LIFETIME_EXP:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_LIFETIME_EXP Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_NO_RELAY diff -u squid/errors/Hebrew/ERR_NO_RELAY:1.3 squid/errors/Hebrew/ERR_NO_RELAY:1.3.6.1 --- squid/errors/Hebrew/ERR_NO_RELAY:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_NO_RELAY Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS diff -u squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3 squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3.6.1 --- squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ONLY_IF_CACHED_MISS Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_READ_ERROR diff -u squid/errors/Hebrew/ERR_READ_ERROR:1.3 squid/errors/Hebrew/ERR_READ_ERROR:1.3.6.1 --- squid/errors/Hebrew/ERR_READ_ERROR:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_READ_ERROR Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_READ_TIMEOUT diff -u squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3 squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3.6.1 --- squid/errors/Hebrew/ERR_READ_TIMEOUT:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_READ_TIMEOUT Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_SHUTTING_DOWN diff -u squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3 squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3.6.1 --- squid/errors/Hebrew/ERR_SHUTTING_DOWN:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_SHUTTING_DOWN Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_SOCKET_FAILURE diff -u squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3 squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3.6.1 --- squid/errors/Hebrew/ERR_SOCKET_FAILURE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_SOCKET_FAILURE Tue Sep 3 10:39:59 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_TOO_BIG diff -u squid/errors/Hebrew/ERR_TOO_BIG:1.3 squid/errors/Hebrew/ERR_TOO_BIG:1.3.6.1 --- squid/errors/Hebrew/ERR_TOO_BIG:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_TOO_BIG Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_UNSUP_REQ diff -u squid/errors/Hebrew/ERR_UNSUP_REQ:1.3 squid/errors/Hebrew/ERR_UNSUP_REQ:1.3.6.1 --- squid/errors/Hebrew/ERR_UNSUP_REQ:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_UNSUP_REQ Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_URN_RESOLVE diff -u squid/errors/Hebrew/ERR_URN_RESOLVE:1.3 squid/errors/Hebrew/ERR_URN_RESOLVE:1.3.6.1 --- squid/errors/Hebrew/ERR_URN_RESOLVE:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_URN_RESOLVE Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ -
ERROR: The requested URN not be retrieved -ùâéàä
A URL for the requested URN could not be retrieved
-
+
While trying to retrieve the URN: %U Index: squid/errors/Hebrew/ERR_WRITE_ERROR diff -u squid/errors/Hebrew/ERR_WRITE_ERROR:1.3 squid/errors/Hebrew/ERR_WRITE_ERROR:1.3.6.1 --- squid/errors/Hebrew/ERR_WRITE_ERROR:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_WRITE_ERROR Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT diff -u squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3 squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3.6.1 --- squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT:1.3 Tue Aug 27 14:45:49 2002 +++ squid/errors/Hebrew/ERR_ZERO_SIZE_OBJECT Tue Sep 3 10:40:00 2002 @@ -1,13 +1,11 @@ -
ùâéàä: äëúåáú äîáå÷ùú ìà ðâéùä -ùâéàä
ìà ðéúï ìâùú àì äëúåáú äîáå÷ùú
-
+
ëàùø ðéñéúé ìâùú àì äëúåáú: %U
Index: squid/errors/Hungarian/ERR_CONFLICT diff -u /dev/null squid/errors/Hungarian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Hungarian/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ +
+ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Italian/ERR_CONFLICT diff -u /dev/null squid/errors/Italian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:35 2004 +++ squid/errors/Italian/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Japanese/ERR_CONFLICT diff -u /dev/null squid/errors/Japanese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Japanese/ERR_CONFLICT Sat Dec 22 08:31:34 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Korean/ERR_CONFLICT diff -u /dev/null squid/errors/Korean/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Korean/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Polish/ERR_CONFLICT diff -u /dev/null squid/errors/Polish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Polish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Portuguese/ERR_CONFLICT diff -u /dev/null squid/errors/Portuguese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Portuguese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Romanian/ERR_CONFLICT diff -u /dev/null squid/errors/Romanian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Romanian/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Russian-1251/ERR_CONFLICT diff -u /dev/null squid/errors/Russian-1251/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Russian-1251/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Russian-koi8-r/ERR_CONFLICT diff -u /dev/null squid/errors/Russian-koi8-r/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Russian-koi8-r/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Serbian/ERR_CONFLICT diff -u /dev/null squid/errors/Serbian/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Serbian/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Simplify_Chinese/ERR_CONFLICT diff -u /dev/null squid/errors/Simplify_Chinese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Simplify_Chinese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Slovak/ERR_CONFLICT diff -u /dev/null squid/errors/Slovak/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Slovak/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Spanish/ERR_CONFLICT diff -u /dev/null squid/errors/Spanish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Spanish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Swedish/ERR_CONFLICT diff -u /dev/null squid/errors/Swedish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Swedish/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Traditional_Chinese/ERR_CONFLICT diff -u /dev/null squid/errors/Traditional_Chinese/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Traditional_Chinese/ERR_CONFLICT Sat Dec 22 08:31:35 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/errors/Turkish/ERR_CONFLICT diff -u /dev/null squid/errors/Turkish/ERR_CONFLICT:1.1.2.1 --- /dev/null Mon Jan 26 04:57:36 2004 +++ squid/errors/Turkish/ERR_CONFLICT Sat Dec 22 08:31:36 2001 @@ -0,0 +1,30 @@ + +ERROR: The requested URL could not be retrieved + +ERROR
+The requested URL could not be retrieved
+
++While trying to retrieve the URL: +%U +
+The following error was encountered: +
+
+ +- + +You made a PUT request with a version that conflicts with +the version already present in the cache. + +
+This means that: +
+When you make a PUT request to a cache, you must supply an object with +a Last-Modified time at least as recent as the version the cache already +has. Otherwise, the version you sent is considered stale and is thrown out. +Either the cache has already received a more recent copy from elsewhere, +or your client push software is computing Last-Modified time incorrectly. ++ + Index: squid/lib/MemPool.c diff -u squid/lib/MemPool.c:1.7 squid/lib/MemPool.c:1.1.46.1 --- squid/lib/MemPool.c:1.7 Fri Aug 9 14:46:00 2002 +++ squid/lib/MemPool.c Tue Sep 3 10:41:24 2002 @@ -80,13 +80,12 @@ * Andres Kroonmaa. */ -#include "config.h" - #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */ #define MEM_MAX_MMAP_CHUNKS 2048 #include+#include "config.h" #if HAVE_STRING_H #include #endif Index: squid/src/HintCache.c diff -u /dev/null squid/src/HintCache.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCache.c Mon May 20 19:46:41 2002 @@ -0,0 +1,460 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 84 Hint cache to Squid interface. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HintCache.c --- High-level interface to hint cache. + *------------------------------------------------------------------ + */ + +#include "squid.h" + +static EVH hintCacheTimer; /* timeout to flush StoreEntries */ + +#define HINT_CACHE_DEBUG 84 + +/* + * Globals + */ +#if USE_DYNAMIC_HIERARCHY +HintCacheNet *parentOutgoingA = NULL; +HintCacheNet *childrenOutgoingA = NULL; +HintCacheNet *neighborsOutgoing = NULL; +#endif +HintCacheDisk *hcDisk = NULL; + + +/* + *------------------------------------------------------------------ + * + * hintCacheInit -- + * + * description. + * + * Results: + * Return nonzero on error. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheInit() +{ + peer *e; +#if USE_DYNAMIC_HIERARCHY + int ii; +#endif + + hcDisk = (HintCacheDisk *) xmalloc(sizeof(HintCacheDisk)); + assert(hcDisk); + hintCacheDiskInit(hcDisk, Config.Hints.cache_file); + +#if USE_DYNAMIC_HIERARCHY + /* + * Three sets of network buffers. Children and parents + * are the children and parents as determined by the + * dynamic hierarchy algorithm (HCHier.h). Neighbors + * are static squid neighbors (neighbors.h). The + * static neighbors are used to bootstrap the + * dynamic algorithm. + */ + neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet)); + assert(neighborsOutgoing); + hintCacheNetInit(neighborsOutgoing); + hintCacheHierInit(); + + childrenOutgoingA = + (HintCacheNet *) xmalloc(sizeof(HintCacheNet) * + hintCacheHier_NChildrenQs()); + assert(childrenOutgoingA); + for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) { + hintCacheNet_Init(&childrenOutgoingA[ii]); + } + parentOutgoingA = + (HintCacheNet *) xmalloc(sizeof(HintCacheNet) * + hintCacheHier_NParentQs()); + assert(parentOutgoingA); + for (ii = 0; ii < hintCacheHierNParentQs(); ii++) { + hintCacheNetInit(&parentOutgoingA[ii]); + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) + hintCacheNetInit(&e->hcoutq); +#endif + + /* Start hint timer */ + eventAdd("hint timer", hintCacheTimer, NULL, + (double) (squid_random() % Config.Hints.intvl), 1); + + return 0; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheDestroy -- + * + * Shut down. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheDestroy() +{ +#if USE_DYNAMIC_HIERARCHY + int ii; + + for (ii = 0; ii < hintCacheHier_NChildrenQs(); ii++) { + hintCacheNetDestroy(&childrenOutgoingA[ii]); + } + xfree(childrenOutgoingA); + childrenOutgoingA = NULL; + for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) { + hintCacheNetDestroy(&parentOutgoingA[ii]); + } + xfree(parentOutgoingA); + parentOutgoingA = NULL; + hintCacheNetDestroy(neighborsOutgoing); + xfree(neighborsOutgoing); + neighborsOutgoing = NULL; +#endif + + hintCacheHierDestroy(); + + hintCacheDiskClose(hcDisk); + xfree(hcDisk); + hcDisk = NULL; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheCreate -- + * + * Create a NEW disk cache (obliterating the one + * already on disk, if any). Then do normal initialization. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheCreate(void) +{ + if (access(Config.Hints.cache_file, R_OK | W_OK) == -1) + hintCacheDiskCreateFile(Config.Hints.cache_file, Config.Hints.size, + Config.Hints.assoc); + + hintCacheInit(); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheinformLocalCopy -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheInformLocalCopy(StoreEntry * entry) +{ + char *url = entry->mem_obj->url; + struct sockaddr_in *me; + HintCacheEntry myentry; + URLKey *key; + HintCacheUpdate update; + + debug(HINT_CACHE_DEBUG, 5) ("hintCacheinformLocalCopy: got %s\n", + url); + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + if (strstr(url, "//updates")) + /* Routes handle their own updates */ + return; + + me = &Config.Sockaddr.http->s; + + /* Prepare data structures */ + key = HINT_CACHE_KEY(entry); + hintCacheEntryInit(&myentry, *key, me, entry->lastmod); + hintCacheUpdateInit(&update, HC_InformToParent, &myentry, 0); + + /* + * Update local and remote hint caches. + */ + hintCachePropHandleInformToParent(&update, me, 1); + update.action = HC_InformToChild; + hintCachePropHandleInformToChild(&update, me, 1); +} + +void +hintCacheInvalLocalCopy(StoreEntry * entry) +{ + struct sockaddr_in *me; + HintCacheEntry myentry; + HintCacheUpdate update; + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + me = &Config.Sockaddr.http->s; + + /* Prepare data structures */ + hintCacheEntryInit(&myentry, *HINT_CACHE_KEY(entry), + me, entry->lastmod); + hintCacheUpdateInit(&update, HC_InvalToParent, &myentry, 0); + + /* + * Update local and remote hint caches. + */ + hintCacheHandleInvalToParent(&update, me, 1); + update.action = HC_InvalToChild; + hintCachePropHandleInvalToChild(&update, me, 1); + + debug(HINT_CACHE_DEBUG, 5) ("hintCacheinvalLocalCopy: lost 0x%qx\n", + ((URLKey *) &entry->hchash.key)->key); +} + + +/* + *------------------------------------------------------------------ + * + * hintCachefindNearest -- + * + * Find the nearest copy of the specified URL. + * Return a copy of the location in *saddr. + * Return the saddr pointer if we found a copy + * or return NULL if no copy found. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------3.24.1998----------- + */ +struct sockaddr_in * +hintCacheFindNearest(StoreEntry *entry, struct sockaddr_in *saddr) +{ + const struct sockaddr_in *me; + URLKey *urlKey; + HintCacheEntry nearest; + int found; + + if (!HINT_CACHE_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return (NULL); + } + + urlKey = HINT_CACHE_KEY(entry); + found = hintCacheDiskFindNearest(hcDisk, *urlKey, &nearest); + if (!found) + return NULL; + + saddr->sin_family = AF_INET; + saddr->sin_port = nearest.port; + saddr->sin_addr = nearest.ipaddr; + + /* Never return ourselves. */ + me = &Config.Sockaddr.http->s; + if (saddr->sin_port == me->sin_port) { + if (saddr->sin_addr.s_addr == me->sin_addr.s_addr) + return NULL; + if (saddr->sin_addr.s_addr == 0x7f000000) + return NULL; + } +#if 0 /* Fixed? */ + /* XXX - shouldn't be needed, but is - noted in BUGS */ + /* Swap bytes to host format. */ + saddr->sin_addr.s_addr = ntohl(saddr->sin_addr.s_addr); + saddr->sin_port = ntohs(saddr->sin_port); +#endif + debug(HINT_CACHE_DEBUG, 5) ("hintCachefindNearest: %s is at <%s,%d>\n", + entry->mem_obj->url, inet_ntoa(saddr->sin_addr), saddr->sin_port); + return (saddr); +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheTimer -- + * + * This gets called every so often. Its job is + * to flush outgoing messages. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +hintCacheTimer(void *junk) +{ + struct sockaddr_in sin; +#if USE_DYNAMIC_HIERARCHY + struct sockaddr_in *childSinA = NULL; + static int nextjoin = 0; + int nchildren, ichild; + int error; + int ii; +#else + peer *e; +#endif + + /* Reload timer */ + eventAdd("hint timer", hintCacheTimer, NULL, + (double) (squid_random() % Config.Hints.intvl), 1); + +#if USE_DYNAMIC_HIERARCHY + /* Process peers */ + /* Send enqueued updates */ + if (parentOutgoingA != NULL) { + for (ii = 0; ii < hintCacheHier_NParentQs(); ii++) { + if (hintCacheNetBytesReady(&parentOutgoingA[ii]) > + sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&parentOutgoingA[ii]); + error = hintCacheHierGetParentAddr(ii, &sin); + debug(HINT_CACHE_DEBUG, 6) + ("Sending %d bytes from parentOutgoing[%d] to %s %s\n", + hintCacheNetbytesReady(&parentOutgoingA[ii]), ii, + inet_ntoa(sin.sin_addr), error ? "ERROR" : ""); + if (!error) { + hintCacheNetSendTo(&parentOutgoingA[ii], &sin); + } + hintCacheNetDone(&parentOutgoingA[ii]); + } + } + } + if (childrenOutgoingA != NULL) { + for (ii = 0; ii < hintCacheHierNChildrenQs(); ii++) { + if (hintCacheNet_bytesReady(&childrenOutgoingA[ii]) > + sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&childrenOutgoingA[ii]); + nchildren = hintCacheHierGetChildAddrs(ii, &childSinA); + debug(HINT_CACHE_DEBUG, 6) + ("Sending %d bytes to %d children from childrenOutgoing[%d]:", + hintCacheNetBytesReady(&childrenOutgoingA[ii]), nchildren, + ii); + + for (ichild = 0; ichild < nchildren; ichild++) { + debug(HINT_CACHE_DEBUG, 8) (" %s ", + inet_ntoa(childSinA[ichild].sin_addr)); + hintCacheNetSendTo(&childrenOutgoingA[ii], + &childSinA[ichild]); + } + + hintCacheNetDone(&childrenOutgoingA[ii]); + xfree(childSinA); + } + } + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (hintCacheNetBytesReady(&e->hcoutq) > sizeof(HintCacheNetHeader)) { + hintCacheNetComplete(&e->hcoutq); + sin.sin_addr = e->in_addr.sin_addr; + sin.sin_port = e->http_port; + hintCacheNetSendTo(&e->hcoutq, &sin); + hintCacheNetDone(&e->hcoutq); + } + } +#endif /* USE_DYNAMIC_HIERARCHY */ + + +#if USE_DYNAMIC_HIERARCHY + /* + * Send out Joins once every few hours. + */ + if (hintCacheNodelistMyStatus() == HC_Join) { + if (squid_curtime >= nextjoin) { + hintCacheNodelistLocalJoin(); + nextjoin = + squid_curtime + (squid_random() % Config.Hints.join_intvl); + } + } +#endif + +#ifdef DOTEST + if (0) { /* XXX */ + if (!hintCacheHierSelfTestDone) { + hintCacheHierTestNetwork(); + } + } +#endif +} Index: squid/src/HintCacheDisk.c diff -u /dev/null squid/src/HintCacheDisk.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheDisk.c Mon May 20 19:46:41 2002 @@ -0,0 +1,817 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 82 On-disk hint cache + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HintCacheDisk --- + * The on-disk cache of hints. The key data structure + * is an mmapped array which is treated as a - + * associative cache. + * + *------------------------------------------------------------------ + */ +#include "squid.h" + +#define HCDISK_DEBUG 82 + +#define BIG_ENOUGH 1024 + +static const char *suffix = ".hints"; + +static int readLine(int fd, char *buffer, int max); +static void initializeFile(int dataFD, int nbuckets, int associativity); +static int findKey(HintCacheDisk * d, int b, URLKey key, + HintCacheDiskEntry * foundRet); +static int deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * oldEntry, + HintCacheDiskEntry * survivingEntry); +static void insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * newEntry); +#ifdef MADV_RANDOM +static caddr_t pageAddr(caddr_t e); +#endif +static void sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp, + HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch); +static int bucket(HintCacheDisk * d, URLKey key); +static HintCacheDiskEntry *readBucket(HintCacheDisk * d, int b); +static int writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp); +#ifdef DOTEST +static void timeMadvise(); +#endif + +static long pageSize; + +/* + * Should we try to keep stuff we just read or wrote in the cache. + */ +/* + * You may not want to cache writes since they may or may not + * be about stuff you will later read. On the other hand, there + * may be temporal locality about stuff that gets updated -- + * I may be likely to read or discard the object in the near + * future. Also, telling system to kick it out of cache costs + * about 1ms per call. + */ +static const int CACHE_RECENT_WRITES = 1; +/* + * You may not want to cache reads since these are things + * that you will now have in your cache (so why would + * you look at the hints any time soon. On the other hand, + * telling system to kick out reads costs about 1ms per call + */ +static const int CACHE_RECENT_READS = 0; +/* + * You may not want to prefetch at all (we can only prefetch + * on network updates, and those are not on critical + * path anywhere. Maybe better to sacrifice latency for + * reduced overhead. + * + * No point int trying to pipeline if there are not many + * updates to pipeline. Otherwise the overhead of the + * system calls outweighs the reduced latency for disk + * reads. In the best case, madvise (tight loop of madvise + * about same location), madvise appears to take about 1ms per call. + */ +static const int DO_PREFETCH = 0; + +/* HintCacheDisk constructor */ +void +hintCacheDiskInit(HintCacheDisk * d, char *diskPath) +{ + int header; + int dataF; + char buffer[BIG_ENOUGH], token[BIG_ENOUGH], dataFile[BIG_ENOUGH]; + int version; + int size, buckets, associativity; + int gotVersion = 0, gotData = 0, gotAssoc = 0, gotSize = 0, gotBuckets = 0; + + if ((pageSize = sysconf(_SC_PAGESIZE)) < 0) { + perror("Cannot determine page size\n"); + exit(-1); + } + + header = open(diskPath, O_RDONLY); + if (header < 0) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t open %s, hint caching disabled\n", diskPath); + HCDisk = NULL; + return; + } + + while (readLine(header, buffer, BIG_ENOUGH)) { + if (buffer[0] != '#') { + sscanf(buffer, "%s", token); + if (!strcmp(token, "VERSION")) { + gotVersion = sscanf(buffer, "VERSION %d\n", &version); + assert(gotVersion == 1); + assert(version == HCD_VERSION); + } else if (!strcmp(token, "DATA_FILE")) { + gotData = sscanf(buffer, "DATA_FILE %s\n", dataFile); + assert(gotData == 1); + } else if (!strcmp(token, "SIZE_BYTES")) { + gotSize = sscanf(buffer, "SIZE_BYTES %d\n", &size); + assert(gotSize == 1); + } else if (!strcmp(token, "BUCKETS")) { + gotBuckets = sscanf(buffer, "BUCKETS %d\n", &buckets); + assert(gotBuckets == 1); + } else if (!strcmp(token, "ASSOCIATIVITY")) { + gotAssoc = sscanf(buffer, "ASSOCIATIVITY %d\n", &associativity); + assert(gotAssoc == 1); + } else { + /* Ignore what we don't understand */ + } + } + } + close(header); + assert(gotVersion && gotData && gotAssoc && gotSize && gotBuckets); + assert(size == buckets * associativity * sizeof(HintCacheDiskEntry)); + d->nbuckets = buckets; + d->entriesPerBucket = associativity; + dataF = open(dataFile, O_RDWR); + if (dataF < 0) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t open %s, hint caching disabled\n", dataFile); + HCDisk = NULL; + return; + } + if (Config.onoff.hint_cache_use_mmap) { + d->mmappedArray = + (HintCacheDiskEntry *) mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, dataF, 0); + if (!d->mmappedArray) { + debug(HCDISK_DEBUG, 1) + ("warning: Can\'t mmap %s, hint caching disabled\n", dataFile); + HCDisk = NULL; + return; + } +#ifdef MADV_RANDOM + if (madvise((char *) d->mmappedArray, size, MADV_RANDOM)) { + debug(HCDISK_DEBUG, 1) + ("warning: madvise on hint cache data failed"); + } +#endif + close(dataF); + d->fd = -1; + } else { + d->fd = dataF; + } +} + +/* + * Read one line of input from file. We really want + * to use fgets(), but the fopen() etc. routines + * don't work if you have large numbers of + * files open (60 or 255 are the max for some implementations). + * So, we use the basic open/read/close routines + * instead, which let us open up to the max number + * of allowed file descriptors. + * + * Store a line of text ending with \n\0 in buffer + * and return nonzero if we succeeded in getting + * a well-formed line. + */ +static int +readLine(int fd, char *buffer, int max) +{ + ssize_t got; + int count = 0; + + assert(buffer); + assert(fd >= 0); + assert(fd <= 10000); + assert(max > 2); /* need room for \n\0 */ + + while (count < max - 2) { + got = read(fd, &buffer[count], 1); + if (got != 1) { + return 0; + } + if (buffer[count] == '\n') { + buffer[count + 1] = '\0'; + return 1; + } + count++; + } + return 0; +} + +/* + * Does the hard work of setting up a new empty file. + * + * Note: we use raw open() and write() rather than + * fopen() and fwrite() because the f-routines + * get unhappy in programs that open lots of files + * (they often die if you have more than 60 or 255 + * files open, even if you are allowed to + * have more open file descriptors than that). + */ +void +hintCacheDiskCreateFile(char *hcPath, int size, int associativity) +{ + char *dataPath; + int buckets; + int headerF, dataF; + char buffer[BIG_ENOUGH]; + int len; + + len = strlen(hcPath); + dataPath = (char *) xmalloc(len + strlen(suffix) + 1); + assert(dataPath); + snprintf(dataPath, len, "%s%s", hcPath, suffix); + + buckets = (size / associativity) / sizeof(HintCacheDiskEntry); + assert(buckets * associativity * sizeof(HintCacheDiskEntry) <= size); + size = buckets * associativity * sizeof(HintCacheDiskEntry); + + headerF = open(hcPath, O_WRONLY | O_CREAT | O_TRUNC, 0744); + if (headerF < 0) { + perror("Opening Hint Cache header"); + exit(-1); + } + + snprintf(buffer, BIG_ENOUGH, + "# *** Header for hint cache. Do not modify ***\n"); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "VERSION %d\n", HCD_VERSION); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "DATA_FILE %s\n", dataPath); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "SIZE_BYTES %d\n", size); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "BUCKETS %d\n", buckets); + write(headerF, buffer, strlen(buffer)); + snprintf(buffer, BIG_ENOUGH, "ASSOCIATIVITY %d\n", associativity); + write(headerF, buffer, strlen(buffer)); + + close(headerF); + + /* Open data file */ + dataF = open(dataPath, O_WRONLY | O_CREAT | O_TRUNC, 0744); + if (dataF < 0) { + perror("Opening Hint Cache data"); + exit(-1); + } + + /* Need to pre-extend file to 'size' */ + lseek(dataF, size - 1, 0); + write(dataF, "\0", 1); + lseek(dataF, 0, 0); + + initializeFile(dataF, buckets, associativity); + close(dataF); + xfree(dataPath); +} + +/* Set a file to empty by invalidating all entries. */ +static void +initializeFile(int fd, int nbuckets, int associativity) +{ + HintCacheDiskEntry invalidEntry; + int ibucket, ientry; + int count; + + HCE_INVALIDATE(&invalidEntry.entry); + + for (ibucket = 0; ibucket < nbuckets; ibucket++) { + for (ientry = 0; ientry < associativity; ientry++) { + count = write(fd, &invalidEntry, sizeof(HintCacheDiskEntry)); + if (count != sizeof(HintCacheDiskEntry)) { + perror("ERROR Creating HintCacheCache file"); + exit(-1); + } + } + } +} + +/* Unmap the file. */ +void +hintCacheDiskClose(HintCacheDisk * d) +{ + munmap((char *) d->mmappedArray, d->nbuckets * d->entriesPerBucket); + d->mmappedArray = NULL; +} + +/* Update data structures to reflect the fact a copy is cached locally. */ +void +hintCacheDiskInformLocal(HintCacheDisk * d, URLKey key, unsigned mtime) +{ + int b; + HintCacheDiskEntry new, dummyRet, old; + int foundOld; + + assert(d); + + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return; + } + + b = bucket(d, key); + foundOld = findKey(d, b, key, &old); + if (foundOld) { + /* Delete old instead of replace to support multiversioning */ + deleteKey(d, b, &old, &dummyRet); + } + hintCacheEntryInit(&new.entry, key, &Config.Sockaddr.http->s, mtime); + new.rtime = squid_curtime; + insertKey(d, b, &new); +#ifdef MADV_RANDOM + if (!CACHE_RECENT_WRITES) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n"); + } + } +#endif +} + + + +/* Update local data structures to reflect the fact + * that we no longer have a copy locally. */ +void +hintCacheDiskInvalLocal(HintCacheDisk * d, URLKey key, unsigned mtime) +{ + HintCacheDiskEntry myent, dummyRet; + int b; + + debug(HCDISK_DEBUG, 2) ("HintCacheDiskinvalLocalCopy: deleting %ll\n", + key.key); + + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return; + } + + hintCacheEntryInit(&myent.entry, key, &Config.Sockaddr.http->s, mtime); + myent.rtime = squid_curtime; + b = bucket(d, key); + deleteKey(d, b, &myent, &dummyRet); +#ifdef MADV_RANDOM + if (Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("Madvise DONTNEED failed\n"); + } + } +#endif +} + +/* Warn vm system that certain pages will be needed. These pages + * hold or will hold object mentioned in this hint update. */ +void +hintCacheDiskprefetch(HintCacheDisk * d, HintCacheUpdate * uArray, int nupdates) +{ +#ifdef MADV_RANDOM + int b; + int ii; + if (DO_PREFETCH && Config.onoff.hint_cache_use_mmap) { + for (ii = 0; ii < nupdates; ii++) { + if (uArray[ii].action == HC_InvalToParent || + uArray[ii].action == HC_InvalToChild || + uArray[ii].action == HC_InformToParent || + uArray[ii].action == HC_InformToChild) { + b = bucket(d, uArray[ii].entry.key); + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_WILLNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise WILLNEED failed\n"); + } + } + } + } +#endif +} + +/* + * The network told us that is + * no longer a valid mapping. If we knew of a + * different copy than the one that was invalidated + * then report that back by returning 1 and putting + * a copy of the survivor in survivor. + * + * The function takes HCEntrys as args rather than + * HintCacheDiskEntrys because it is called exclusively + * from outside HintCacheDisk.c. + */ +int +hintCacheDisknetInvalRecord(HintCacheDisk * d, + HintCacheEntry * entry, HintCacheEntry * survivor) +{ + HintCacheDiskEntry dentry, dsurv; + int remainingCopy; + int b; + + if (!HCE_VALID(entry)) { + survivor->key.key = 0; + return 0; + } + + dentry.entry = *entry; + dentry.rtime = squid_curtime; + + b = bucket(d, entry->key); + remainingCopy = deleteKey(d, b, &dentry, &dsurv); + *survivor = dsurv.entry; +#ifdef MADV_RANDOM + if (Config.onoff.hint_cache_use_mmap) + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + debug(HCDISK_DEBUG, 1) ("madvise DONTNEED failed\n"); + } +#endif + + return remainingCopy; +} + +/* + * The network told us that is a valid + * mapping. Install it if it is better than the one + * we have. + * + * Takes HintCacheEntrys as args because it's exported. + */ +int +hintCacheDiskUpdateIfCloser(HintCacheDisk * d, HintCacheEntry * new) +{ + HintCacheDiskEntry old, dummyRet, dnew, *todelete; + URLKey key = new->key; + int dochange = 0; + StoreEntry *e; + int ret = 0; + int foundOld; + int b; + + if (!HCE_VALID(new)) { + return 0; + } + + dnew.entry = *new; + dnew.rtime = squid_curtime; + + b = bucket(d, key); + foundOld = findKey(d, b, key, &old); + if (!foundOld) { + insertKey(d, b, &dnew); + todelete = &dnew; + ret = 1; + } else + todelete = &old; + + e = hintCacheStoreGet(key); + if (e && e->lastmod < new->mtime) { + /* This hint is about a new version. Invalidate the old version */ + storeRelease(e); + dochange = 1; + } else if (foundOld && squid_curtime >= old.rtime + Config.Hints.holddown) { + /* Don't propagate hints about the same version more often + * that once every fifteen minutes. */ + dochange = 1; + } else if (hintCacheHierCompareDistance(new->ipaddr, old.entry.ipaddr) < 0) { + /* This hint is for cache closer than what we got */ + dochange = 1; + } + + if (dochange) { + deleteKey(d, b, todelete, &dummyRet); + insertKey(d, b, &dnew); + ret = 1; + } +#ifdef MADV_RANDOM + if (!CACHE_RECENT_WRITES && Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + perror("Madvise DONTNEED failed\n"); + } + } +#endif + return ret; +} + +/* + * Find the record for the key if one exists. Return 1 + * if matching record found and a copy in *match. + * Return 0 if no match found. + * + * Note: we can't just return a pointer to match + * because its location in the bucket can change + * at any time. + * + * Takes HintCacheEntry as arg because it is exported. + */ +int +hintCacheDiskFindNearest(HintCacheDisk * d, URLKey key, HintCacheEntry * match) +{ + int b; + int found; + HintCacheDiskEntry dent; + + assert(match != 0); + if (!URLKEY_COMPARE(key, INVALID_URL_KEY)) { + return 0; + } + + b = bucket(d, key); + found = findKey(d, b, key, &dent); + if (found) + *match = dent.entry; +#ifdef MADV_RANDOM + if (!CACHE_RECENT_READS && Config.onoff.hint_cache_use_mmap) { + if (madvise(pageAddr((caddr_t) (d->mmappedArray + b)), + pageSize, MADV_DONTNEED)) { + perror("Madvise DONTNEED failed\n"); + } + } +#endif + return found; +} + + +/* Return pointer to first entry in bucket for key. */ +static int +bucket(HintCacheDisk * d, URLKey key) +{ + int b; + + b = key.key % d->nbuckets; + return b * d->entriesPerBucket; +} + +#ifdef MADV_RANDOM +/* + * Return the address of the first byte of the + * page that holds an address. + */ +static caddr_t +pageAddr(caddr_t e) +{ + caddr_t ret; + ret = e - ((unsigned) e % pageSize); + return ret; +} +#endif /* MADV_RANDOM */ + +/* + * Delete the record associated with the specified + * pair. + * + * If there is a record for the key that survives the + * delete (e.g. the node doesn't match) return it + * in the HintCacheEntry *surviver field and return 1. If + * no record for the key survives the delete, return 0. + * + * Note: we can't just return a pointer to survivor + * because its location in the bucket can change + * at any time. + */ +static int +deleteKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry, + HintCacheDiskEntry * survivor) +{ + HintCacheDiskEntry *bucketp = d->mmappedArray + b; + int ii; + + assert(survivor != NULL); + assert(entry != survivor); + assert(HintCacheE_VALID(&entry->entry)); + + bucketp = readBucket(d, b); + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) { + if (!HCEntry_Compare(&entry->entry, &bucketp[ii].entry)) { + HCE_INVALIDATE(&bucketp[ii].entry); + sanityCheckMatch(d, bucketp, entry, 0, 0); + break; + } else { + /* + * Matched key but not NodeId. + */ + *survivor = bucketp[ii]; + sanityCheckMatch(d, bucketp, entry, 0, 1); + sanityCheckMatch(d, bucketp, survivor, 1, 1); + return 1; + } + } + } + writeBucket(d, b, bucketp); + /* + * No match key + */ + return 0; +} + + +/* + * Insert an entry in a given bucket in hash table. + * The table is n-way associative. The new entry + * is always inserted into entry 0, and the remaining + * entries are shifted up. If there is an empty + * entry, we don't have to shift any higher entries. + * If all entries are full, entry d->entriesPerBucket - 1 + * (the last entry) is lost. + */ +static void +insertKey(HintCacheDisk * d, int b, HintCacheDiskEntry * entry) +{ + HintCacheDiskEntry *bucketp; + int from, to; + + /* Get bucket */ + bucketp = readBucket(d, b); + + /* + * Caller responsible for deleting old entry before inserting + * a new one. + */ + sanityCheckMatch(d, bucketp, entry, 0, 0); + + /* + * First, see if there are any empty entries. All entries + * below the first empty one get shifted up to make + * room in entry 0. The last entry by definition is + * emtpy if all earlier ones are empty (you are always + * allowed to shift over the last entry.) + */ + for (to = 0; to < d->entriesPerBucket - 1; to++) { + if (!HCE_VALID(&bucketp[to].entry)) { + break; + } + } + assert(to <= d->entriesPerBucket - 1); + assert(!HCE_VALID(&bucketp[to].entry) || (to == d->entriesPerBucket - 1)); + + /* + * Shift entry up to entry to make entry 0 empty. + * The last bucket we shift is entry (from==entriesPerBucket-2) + * which shifts into the last bucket (entriesPerBucket-1). + * Don't go any farther, or we clobber the next bucket. + */ + for (; to > 0; to--) { + from = to - 1; + assert(from >= 0); + bucketp[to] = bucketp[from]; + } + bucketp[0] = *entry; + sanityCheckMatch(d, bucketp, entry, 1, 1); + writeBucket(d, b, bucketp); +} + +/* + * Check to see that the expected number of entries in bucket + * match specified key. + */ +static void +sanityCheckMatch(HintCacheDisk * d, HintCacheDiskEntry * bucketp, + HintCacheDiskEntry * entry, int expectFullMatch, int expectKeyMatch) +{ + int ii; + int fullMatch = 0, keyMatch = 0; + + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!hintCacheEntryCompare(&bucketp[ii].entry, &entry->entry)) { + fullMatch++; + } + if (!URLKEY_COMPARE(bucketp[ii].entry.key, entry->entry.key)) { + keyMatch++; + } + } + assert(fullMatch == expectFullMatch); + assert(keyMatch == expectKeyMatch); +} + +/* + * Find an entry that matches the key. Return + * true if found and put the result in foundRet. + * Since this is a read, + * update the LRU list by removing key and + * then re-inserting key. + * + * Note: we can't just return a pointer to copy + * because its location in the bucket can change + * at any time. + */ +static int +findKey(HintCacheDisk * d, int b, URLKey key, HintCacheDiskEntry * copy) +{ + HintCacheDiskEntry *bucketp; + int ii; + + bucketp = readBucket(d, b); + assert(copy != NULL); + assert(copy < bucketp || copy > &bucketp[d->entriesPerBucket - 1]); + assert(URLKEY_COMPARE(key, INVALID_URL_KEY)); + for (ii = 0; ii < d->entriesPerBucket; ii++) { + if (!URLKEY_COMPARE(bucketp[ii].entry.key, key)) { + *copy = bucketp[ii]; + assert(!URLKEY_COMPARE(copy->entry.key, key)); + if (ii != 0) { + /* + * Move to front of LRU list by deleting entry and inserting + */ + HCE_INVALIDATE(&bucketp[ii].entry); + writeBucket(d, b, &bucketp[ii]); + insertKey(d, b, copy); + } + return 1; + } + } + HCE_INVALIDATE(©->entry); + return 0; +} + +static HintCacheDiskEntry * +readBucket(HintCacheDisk * d, int b) +{ + static HintCacheDiskEntry *bucketp = 0; + int bucketlen; + + /* If using mmap, just return the pointer */ + if (Config.onoff.hint_cache_use_mmap) + return (d->mmappedArray + b); + + /* Get a static buffer to put stuff in */ + bucketlen = sizeof(HintCacheDiskEntry) * d->entriesPerBucket; + if (bucketp == 0) { + bucketp = (HintCacheDiskEntry *) xmalloc(bucketlen); + } + + /* Fetch hint from disk by Unix I/O */ + if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return 0; + } + if (read(d->fd, bucketp, bucketlen) == -1) { + debug(HCDISK_DEBUG, 1) + ("warning: can't read hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return 0; + } + + return bucketp; +} + + +static int +writeBucket(HintCacheDisk * d, int b, HintCacheDiskEntry * bucketp) +{ + /* If using mmap, no action is necessary - model is that + * you modify stuff via direct pointer you got from read */ + if (Config.onoff.hint_cache_use_mmap) + return 0; + + /* Write bucket to disk by Unix I/O */ + if (lseek(d->fd, b * sizeof(HintCacheDiskEntry), 0) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't seek to hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return -1; + } + if (write(d->fd, bucketp, + sizeof(HintCacheDiskEntry) * d->entriesPerBucket) == -1) { + debug(HCDISK_DEBUG, 1) ("warning: can't write hint at offset %d\n", + b * sizeof(HintCacheDiskEntry)); + return -1; + } + + return 0; +} + +void +hcdiskDeleteHintCache() +{ + char hcname[256]; + + if (!Config.Hints.cache_file[0]) + return; + + unlink(Config.Hints.cache_file); + strcpy(hcname, Config.Hints.cache_file); + strcat(hcname, ".theCache"); + unlink(hcname); +} Index: squid/src/HintCacheEndian.c diff -u /dev/null squid/src/HintCacheEndian.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheEndian.c Mon May 20 19:46:41 2002 @@ -0,0 +1,97 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 85 Hint Cache Endianness conversion routines + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCEndian.c --- + * + * HCEndian has the really low-level stuff for transmorifying + * basic types -- long, long long. It is up to each class + * that wants to be able to go across the wire to call + * these primitives on its own fields. + *------------------------------------------------------------------ + */ + +#include "squid.h" +#include + +long long unsigned +HCEndian_llNetToMachine(long long unsigned net) +{ + long unsigned *netLong = (long unsigned *) &net; + long long unsigned machine; + long unsigned *machineLong = (long unsigned *) &machine; + + machineLong[0] = ntohl(netLong[0]); + machineLong[1] = ntohl(netLong[1]); + return machine; +} + + +long long unsigned +HCEndian_llMachineToNet(long long unsigned machine) +{ + long unsigned *machineLong = (long unsigned *) &machine; + long long unsigned net; + long unsigned *netLong = (long unsigned *) &net; + + netLong[0] = htonl(machineLong[0]); + netLong[1] = htonl(machineLong[1]); + return net; +} + + +#ifdef DOTEST +void +HCEndian_selfTest(void) +{ + static const int verbose = 0; + long long unsigned ll1 = (long long unsigned) 0x3BCDEF0213579876; + long long unsigned ll2; + + printf("HCEndian_selfTest."); + if (verbose) { + printf("before: %llx\n", ll1); + } + ll2 = HCEndian_llMachineToNet(ll1); + if (verbose) { + printf("during: %llx\n", ll2); + } + ll2 = HCEndian_llNetToMachine(ll2); + if (verbose) { + printf("after: %llx\n", ll2); + } + assert(ll1 == ll2); + printf("..OK\n"); +} +#endif Index: squid/src/HintCacheHier.c diff -u /dev/null squid/src/HintCacheHier.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheHier.c Mon May 20 19:46:41 2002 @@ -0,0 +1,755 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * DEBUG: section 86, Hint cache hierarchy. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCDisk --- + * The on-disk cache of hints. The key data structure + * is an mmapped array which is treated as a - + * associative cache. + * + *------------------------------------------------------------------ + */ +#include "squid.h" + +/* + * MDD 7.18.1998 + * We use a primitive hierarchy consisting of the edges + * listed in the config file for bootstrapping the real + * hierarchy. Each node floods Join/Leave events to + * neighbors on the peerlist. The peerlist initially comes from + * the config file cache_host entries. We add one thing: + * if node A lists B as a cache host to which it will + * propagate Join/Leave events, we also want B to have + * A on the peerlist. E.g., make all peerlist edges bidirectional + * even if the config file's don't make them bidirectional. + * The reason for this is that if a new node that no current + * nodes have ever heard of joins the system, we of course want to + * propagate membership information to it. E.g, if node D + * adds node A to its config file, that effectively also + * adds node D to A's config file. Otherwise the old nodes + * learn about the new node, but the new node doesn't learn + * about anything. + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + */ + +#define HCHIER_DEBUG 86 + +#ifdef DOTEST +static int doTestBarrier(int barrier); +static void writeTestBarrier(int barrier); +static int readTestBarrier(int barrier); +static void clearTestBarrier(); +static void testFindPeer(peer * p); +static void testPlax(void); +static void testCreateStuff(char *tag); +static void testFind(void); +static void testFindStuff(char *tag, const struct sockaddr_in *expect); +#endif /* DOTEST */ + +/* + * These must be an set of values each one greater than the + * last to define the series of states for the network test. + */ +#define BARRIER_START 1000 +#define BARRIER_READY 1001 +#define BARRIER_JOIN 1002 +#define BARRIER_JOIN2 1003 +#define BARRIER_NODELIST 1004 +#define BARRIER_CREATE_STUFF 1005 +#define BARRIER_CREATE_STUFF2 1006 +#define BARRIER_CREATE_STUFF3 1007 +#define BARRIER_PLAX 1008 +#define BARRIER_FIND 1009 +#define BARRIER_LAST 1010 +#define BARRIER_DONE 9999 + +int HintCacheHier_selfTestDone = 0; + + +dlink_list HintCacheHier_Nodes; + +int scanIDs (dlink_list * l, char *b, int *count); +int scanIDDistances (dlink_list * l, char *b, int *count); + +void +hintCacheHier_Init(void) +{ + HintCacheNodeListIter iter; + struct sockaddr_in saddr; + /* + * This should be set in config file + */ + static int bitsPerLevelXXX = 8; + + HintCacheNodelist_Init(); + HintCachePlax_Init(bitsPerLevelXXX); + HintCacheNodelist_LocalJoin(); + for (HintCacheNodeList_IterStart(&iter); + hintCacheNodeList_IterCheck(iter); hintCacheNodeList_IterNext(&iter)) { + if (hintCacheNodeList_IterGetAddr(iter, &saddr)) { + hintCachePlax_addNode(&saddr); + } + } +} + +void +hintCacheHier_Destroy(void) +{ + hintCacheNodelist_LocalLeave(); + hintCacheNodelist_Destroy(); + hintCachePlax_Destroy(); +} + +/* + *------------------------------------------------------------------ + * MDD 7.18.1998 + * + * HCHier_updateMembershipNeighbor -- + * + * Add the specified node to the peerlist. See HCHier.h + * for explanation. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------7.18.1998--------- + */ +void +hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor, + NeighborAction action) +{ + /* Currently nothing */ +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierCompareDistanceFromMe -- + * + * Return <0 if new node is closer than old node, 0 if same + * distance, >0 if new node is closer than old node. + * If either node is missing, it must be far away. If both + * are missing, say new one is closer (0) (needed to make + * initial sight of new host work). + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old) +{ + int nrtt, ortt; + int nhops, ohops; + char name[16]; + + /* Compare by rtt if both have measured rtts */ + /* Must make copy of result of inet_ntoa before making + * function call because netdb also uses that function */ + strcpy(name, inet_ntoa(new)); + nrtt = netdbHostRtt(name); + strcpy(name, inet_ntoa(old)); + ortt = netdbHostRtt(name); + if (nrtt && ortt) + return (nrtt - ortt); + + /* Otherwise compare hopcount */ + nhops = netdbHintHops(new); + ohops = netdbHintHops(old); + + /* If either host is unknown, say new one is nearer */ + if (nhops == 0 || ohops == 0) + return (-1); + + return (nhops - ohops); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNewNode -- + * + * This gets called when we hear about a new node in the system. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.1.1998----------- + */ +void +hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + hintCacheNodelist_NetJoin(sin, hops, joinTimeNS); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierDelNode -- + * + * This gets called when we hear about a node leaving the system + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.1.1998----------- + */ +void +hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + hintCacheNodelist_NetLeave(sin, hops, joinTimeNS); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierCheckIfParent -- + * + * See if the specified node is really my parent. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_CheckIfParent(key, candidate); +#else + /* + * For static algorithm, anyone that wants to be my parent can + * be. + */ + return 1; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHier_CheckIfChild -- + * + * See if the specified node is really my child. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierCheckIfChild(struct sockaddr_in *candidate) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_CheckIfChild(candidate); +#else + /* + * For static algorithm, anyone that wants to be my child can + * be. + */ + return 1; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierAddChild -- + * + * This node has claimed to by my child, so add it + * to the dynamic hierarchy. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998-------- + */ +void +hintCacheHierAddChild(struct sockaddr_in *child) +{ +#if USE_DYNAMIC_HIERARCHY + hintCachePlax_AddChild(child); +#else + /* + * For static algorithm, I don't track children. + */ + return; +#endif +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierRemoveChild -- + * + * This node denies paternity. Disinherit it. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998---------- + */ +void +hintCacheHierRemoveChild(struct sockaddr_in *child) +{ +#if USE_DYNAMIC_HIERARCHY + hintCachePlax_RemoveChild(child); +#else + /* + * For static algorithm, I don't track children. + */ + return; +#endif +} + + +/* + * Network enqueue/send interface. + */ + +/* Each children queue holds messages that should go to a set of + * "equivalent" children (eg. the children at some level of the + * hierarchy.) There are hintCacheHier_NChildrenQs() such queues; + * Child queue q contains c = hintCacheHier_ChildrenPerQ(q) children. + * The addresses of the children can be found with the function + * hintCacheHier_GetChildAddr(q, c); + * + * Each parent queue holds messages that should go to one parent. + * In general, we may have different parents for different objects. + * So, enqueue messages for an object in the queue + * hintCacheHier_ParentQIndex(URLKey). + */ + +/* + *------------------------------------------------------------------ + * + * hintCacheHierChildQIndex -- + * + * Return the index into the array of queues of + * children for children that are my children + * for this object. (See hintCachePlax for how + * children are grouped into levels.) + * + * Also, if I have no children for this object, + * set amILeaf to true. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------4.10.1998------------- + */ +int +hintCacheHierChildQIndex(URLKey * key, int iAmRoot, int *amILeaf) +{ + assert(amILeaf != NULL); +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_ChildQIndex(key, iAmRoot, amILeaf); +#else + /* + * For static algorithm, we have one set of children and + * thus one outgoing children buffer with index 0. + */ + *amILeaf = 0; + return 0; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNChildrenQs -- + * + * Return the number of outgoing message queues + * to different classes of children. Each + * "class" corresponds to children for which + * I am a parent. (See hintCachePlax for how + * children are grouped into levels.) + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.10.1998------------ + */ +int +hintCacheHierNChildrenQs(void) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlax_NChildrenQs(); +#else + /* + * For static algorithm, we have one set of children and + * thus one outgoing children buffer with index 0. + */ + return 1; +#endif +} + + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierGetChildAddrs -- + * + * Return the number of children for the specified message + * queue, allocate a buffer for that many addresses, + * and fill in that bufer with the children's addresses. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * See above. + * + * Side effects: + * Allocates a vector for the addresses. Caller must free + * this vector when done. + * + * Note: the vector may be out of date by the time ther caller + * uses it. This is inherent problem -- even if caller sent + * all messages instantaneously, by the time they arrive + * at destination, the child could have left the system + * or a new child could have joined. + * + *------------------------------------------------4.16.1998------------ + */ +int +hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP) +{ +#ifndef USE_DYNAMIC_HIERARCHY + peer *p; + int count = 0, nchildren = 0; +#endif + + assert(retAddrAP); + assert(qIndex < hintCacheHierNChildrenQs()); + +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxGetChildAddrs(qIndex, retAddrAP); +#else + assert(qIndex == 0); + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + nchildren++; + } + *retAddrAP = (struct sockaddr_in *) xmalloc(nchildren + * sizeof(struct sockaddr_in)); + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + (*retAddrAP)[count] = p->in_addr; + count++; + } + /* + * Squid promises that we run atomically + */ + assert(count == nchildren); + return nchildren; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierNParentQs -- + * + * How many different message queues are they for different + * parents? + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierNParentQs(void) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxNParentQs(); +#else + /* + * For static algorithm, we have one parent + * thus one outgoing parent buffer with index 0. + */ + return 1; +#endif +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheHierParentQIndex -- + * + * Return the index of the queue I should use to talk + * to the parent for the specified object (set amIRoot + * if I am the root for the object.) + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.10.1998--------- + */ +int +hintCacheHierParentQIndex(URLKey * key, int *amIRoot) +{ + assert(amIRoot != NULL); +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxParentQIndex(key, amIRoot); +#else + /* + * For static algorithm, we have one parent + * thus one outgoing parent buffer with index 0. + */ + *amIRoot = 0; + return 0; +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheHierGetParentAddr -- + * + * Return the address of the node that is curerntly + * the parent for the specified message queue. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * Put answer in *retAddr and return nonzero on error. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +int +hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr) +{ +#if USE_DYNAMIC_HIERARCHY + return hintCachePlaxGetParentAddr(index, retAddr); +#else + peer *p; + + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + if (p->type == PEER_PARENT) { + *retAddr = p->in_addr; + return 0; + } + } + p = getFirstPeer(); + if (p) { + *retAddr = p->in_addr; + return 0; + } + return -1; +#endif +} + + +int +hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate * update, int msgtype) +{ +#if USE_DYNAMIC_HIERARCHY + int stillHave; + int pIndex, cIndex; + int iAmRoot, iAmLeaf; +#else + peer *e; +#endif + +#if USE_DYNAMIC_HIERARCHY + pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot); +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (e->type != PEER_PARENT) + continue; + if (e->in_addr.sin_addr.s_addr == src->sin_addr.s_addr + && e->http_port == src->sin_port) { + if (e->type != PEER_PARENT) { + debug(HCHIER_DEBUG, 0, + "warning: got parental msg from non-parent <%s,%d>.\n", + inet_ntoa(src->sin_addr), src->sin_port); + debug(HCHIER_DEBUG, 0, + " Not propagating it. Configuration mismatch?\n"); + return (-1); + } + continue; + } + hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry, + update->hopcount + 1); + } + if (e == 0) { + /* Not found. */ + return (-1); + /* Don't propagate */ + } +#endif + +#if USE_DYNAMIC_HIERARCHY + /* Send message */ + if (!iAmRoot) { + assert(pIndex < hintCacheHier_NParentQs()); + hintCacheNetEnqueue(&parentOutgoingA[pIndex], msgtype, &update->entry, + update->hopcount + 1); + } +#endif + + return (0); +} + + + +int +hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate * update, + int msgtype, int siblingtype) +{ +#if USE_DYNAMIC_HIERARCHY + int stillHave; + int pIndex, cIndex; + int iAmRoot, iAmLeaf; +#else + peer *e; +#endif + +#if USE_DYNAMIC_HIERARCHY + pIndex = hintCacheHierParentQIndex(&update->entry.key, &iAmRoot); + cIndex = hintCacheHierChildQIndex(&update->entry.key, iAmRoot, &iAmLeaf); + if (!iAmLeaf) { + assert(cIndex < hintCacheHierNChildrenQs()); + hintCacheNetEnqueue(&childrenOutgoingA[cIndex], msgtype, + &update->entry, update->hopcount + 1); + } +#else + for (e = getFirstPeer(); e; e = getNextPeer(e)) { + if (e->in_addr.sin_addr.s_addr != src->sin_addr.s_addr + || e->http_port != src->sin_port) { + if (siblingtype == PEER_NONE || e->type == siblingtype) + hintCacheNetEnqueue(&e->hcoutq, msgtype, &update->entry, + update->hopcount + 1); + } + } +#endif + return (0); +} + + Index: squid/src/HintCacheNet.c diff -u /dev/null squid/src/HintCacheNet.c:1.1.2.3 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheNet.c Mon May 20 19:46:41 2002 @@ -0,0 +1,563 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 87 Hint cache networking. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * hintCacheNet --- Simple send interface built on squid async send stuff. + *------------------------------------------------------------------ + */ + +#include "squid.h" +#include + +#define HCNET_DEBUG 87 + +#define RECV_DEBUG(type, u, hdr, src) \ + debug (HCNET_DEBUG, 2) ("Got %s: 0x%x at <%s,%d> from <%s,%d>\n", \ + (type), *(int *) &(u)->entry.key.key, \ + inet_ntoa((u)->entry.ipaddr), (u)->entry.port, \ + inet_ntoa((src)->sin_addr), (hdr)->httpport) + +static void enqueueBytes(HintCacheNet * n, char *data, int nbytes); +static int copyToLocal(HintCacheUpdate * updatesA, char *data, int len, + int oneUpdateSize); +static void clear(HintCacheNet * n); +static void updateHierarchy(HintCacheUpdate * updatesA, int nupdates, + struct sockaddr_in *source); +static void suppress(HintCacheUpdate * updateA, int nupdates); +static void scoldParent(struct sockaddr_in *parent); + +void +hintCacheNetInit(HintCacheNet * n) +{ +#ifdef DOTEST + n->testMode = 0; + n->testCount = 0; +#endif + clear(n); +} + +static void +clear(HintCacheNet * n) +{ + HintCacheNetHeader hdr; + const char *url = "route://updates"; + request_flags rflags; + StoreEntry *entry; + + assert(n); + + /* Set up entry with request */ + *(unsigned int *) &rflags = 0; + rflags.cachable = 1; + entry = storeCreateEntry(url, url, rflags, METHOD_GET); + n->sendBuffer = entry; + EBIT_SET(entry->flags, ENTRY_SPECIAL); /* formerly set KEEP_INMEM */ +/* EBIT_SET(entry->flags, DONT_FREE_FOR); */ + n->sendBuffer->mem_obj->request = + requestLink(urlParse(METHOD_GET, (char *) url)); + + n->sendLength = 0; + + n->state = HC_filling; + + /* Prepare header for next transmission */ + hdr.httpport = htons(Config.Sockaddr.http->s.sin_port); + hdr.updlen = htons(sizeof(HintCacheUpdateNet)); + enqueueBytes(n, (char *) &hdr, sizeof(hdr)); +} + +void +hintCacheNetDestroy(HintCacheNet * n) +{ + storeRelease(n->sendBuffer); + n->state = HC_destroyed; +} + +void +hintCacheNetEnqueue(HintCacheNet * n, int action, HintCacheEntry * entry, int hopcount) +{ + HintCacheUpdate update; + HintCacheUpdateNet netUpdate; + +#ifdef DOTEST + if (n->testMode) { + n->testCount++; + return; + } +#endif + debug(HCNET_DEBUG, 4) + ("HCNet_Enqueue onto 0x%x (action %d) (entry.key %llx entry.ipaddr %s port %d)\n", + n, action, entry->key.key, inet_ntoa(entry->ipaddr), entry->port); + + hintCacheUpdateInit(&update, action, entry, hopcount); + hintCacheUpdateNetInit(&netUpdate, &update); + enqueueBytes(n, (char *) &netUpdate, sizeof(HintCacheUpdateNet)); +} + +static void +enqueueBytes(HintCacheNet * n, char *data, int nbytes) +{ + static enqreentrancy = 0; + + assert(n->state == HC_filling); + assert(!enqreentrancy); + ++enqreentrancy; + n->sendLength += nbytes; + storeAppend(n->sendBuffer, data, nbytes); + --enqreentrancy; +} + +int +hintCacheNetBytesReady(HintCacheNet * n) +{ + return n->sendLength; +} + +void +hintCacheNetComplete(HintCacheNet * n) +{ + + assert(n); + assert(n->state == HC_filling); + n->state = HC_full; + hintCacheFinishHeader(n->sendBuffer); + storeComplete(n->sendBuffer); +} + +void +hintCacheNetSendTo(HintCacheNet * n, struct sockaddr_in *dest) +{ + assert(n->state == HC_full); + assert(n->sendLength > sizeof(HintCacheNetHeader)); + debug(HCNET_DEBUG, 2) ("HCNet_SendTo: sending routes on 0x%x to <%s,%d>\n", + n, inet_ntoa(dest->sin_addr), dest->sin_port); + putSend(n->sendBuffer, dest, NULL, NULL, 0); +} + +void +hintCacheNetDone(HintCacheNet * n) +{ + StoreEntry *entry = n->sendBuffer; + + assert(n->state == HC_full); + + EBIT_CLR(entry->flags, ENTRY_SPECIAL); /* formerly KEEP_INMEM flag */ + + EBIT_SET(entry->flags, RELEASE_REQUEST); + storeUnlockObject(entry); + + clear(n); +} + + +#ifdef DOTEST +void +hintCacheNetSetTestMode(HintCacheNet * n) +{ + n->testMode = 1; + n->testCount = 0; +} + +int +hintCacheNetGetTestCount(HintCacheNet * n) +{ + return n->testCount; +} +#endif /* DOTEST */ + +/* + *------------------------------------------------------------------ + * + * hintCacheNetDataArrives -- + * + * Action to take when messages arrive from network. + * + * Arguments: + * char *data -- unaligned buffer of network-formatted hintCacheNetUpdates + * int len -- number of bytes in that buffer + * struct sockaddr *source -- who sent the buffer + * + * Results: + * None. + * + * Side effects: + * Many. + * + *------------------------------------------------4.2.1998------------ + */ +void +hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader * hdr, + struct sockaddr_in *source) +{ + struct sockaddr_in sin; + HintCacheUpdate *updatesA; + int nupdates; + int iupdate; + + if (!HC_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + assert(source->sin_family == AF_INET); + assert(hdr->updlen >= HCU_MINLEN); + + debug(HCNET_DEBUG, 3) + ("HintCacheDataArrives: got %d bytes of stuff (probably %d updates xtra=%d\n", + len, len / hdr->updlen, len % hdr->updlen); + + /* Copy to alignment buffer and local format */ + updatesA = (HintCacheUpdate *) xmalloc(len); + nupdates = copyToLocal(updatesA, data, len, hdr->updlen); + + /* + * Suppress loops. Better to do this on send-side, but + * this should be uncommon --> no performance impact + */ + suppress(updatesA, nupdates); + + /* + * Help hierarchy learn about who our children are. + */ + source->sin_port = hdr->httpport; + + updateHierarchy(updatesA, nupdates, source); + + /* + * Prefetch if we have a large number of requests. + * Idea is to tell OS to start bringing in the pages + * that we are about to touch. + */ + if (nupdates >= HCD_PREFETCH_THRESH) { + hintCacheDisk_prefetch(hcDisk, updatesA, nupdates); + } + + /* + * OK. Now we can start processing the messages. + */ + for (iupdate = 0; iupdate < nupdates; iupdate++) { + switch (updatesA[iupdate].action) { + case HC_InvalToParent: + RECV_DEBUG("hintCache_InvalToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InvalToChild: + RECV_DEBUG("hintCache_InvalToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToChild(&updatesA[iupdate], source, 0); + break; + + case HC_InformToParent: + RECV_DEBUG("hintCache_InformToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInformToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InformToChild: + RECV_DEBUG("hintCache_InformToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInformToChild(&updatesA[iupdate], source, 0); + break; + + case HC_Join: + /* New cache node! Add to list. */ + RECV_DEBUG("hintCache_Join", &updatesA[iupdate], hdr, source); + /* + * MDD 7.18.1998 + * When a node relays a join/leave to us, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + sin.sin_family = AF_INET; + sin.sin_addr = source->sin_addr; + sin.sin_port = hdr->httpport; + hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_ADD); + + /* + * Now update local state for join + */ + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + hintCacheHier_newNode(&sin, updatesA[iupdate].hopcount, + updatesA[iupdate].entry.key.key); + break; + + case HC_Leave: + /* Cache node is either dead or has been detected dead. */ + RECV_DEBUG("hintCache_Leave", &updatesA[iupdate], hdr, source); + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + hintCacheHier_delNode(&sin, updatesA[iupdate].hopcount, + updatesA[iupdate].entry.key.key); + + /* + * MDD 7.18.1998 + * When we receive a join from a node, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + hintCacheHier_updateMembershipNeighbor(source, NEIGHBOR_ADD); + /* + * MDD 7.18.1998 + * And the node we just heard about is gone, so it must + * no longer be a neighbor across which to propagate changes + * in membership. + */ + hintCacheHier_updateMembershipNeighbor(&sin, NEIGHBOR_REMOVE); + + break; + + case HC_NotChild: + /* + * This message should have been handled and suppressed + * (by making it "HC_Ignore") in the updateHierarchy() code. + */ + RECV_DEBUG("HC_NotChild", &updatesA[iupdate], hdr, source); + assert(0); + break; + + case HC_Ignore: + /* This message was suppressed either because it is + * part of a loop or because it came from a node that + * thinks it is my parent but isnt. + */ + break; + + default: + /* Ignore bad messages */ + debug(HCNET_DEBUG, 1) + ("HCHintCache: unknown update action %d from net\n", + updatesA[iupdate].action); + break; + } + } + + xfree(updatesA); +} + +/* + *------------------------------------------------------------------ + * + * copyToLocal -- + * + * Copy unaligned network-format buffer to aligned, local format + * array of updates + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * Nelements + * + * Side effects: + * Copies data into udpatesA + * + *-----------------------------------------------3.31.1998----------- + */ +static int +copyToLocal(HintCacheUpdate * updatesA, char *data, int len, int oneUpdateSize) +{ + char *alignbuf; + int uoff; + HintCacheUpdateNet *nupdatep; + int ii; + + alignbuf = xmalloc(len); + memcpy(alignbuf, data, len); + + for (uoff = 0, ii = 0; uoff < len; uoff += oneUpdateSize, ii++) { + nupdatep = (HintCacheUpdateNet *) (alignbuf + uoff); + hintCacheUpdateNetLocalFormat(nupdatep, &updatesA[ii]); + } + xfree(alignbuf); + return ii; +} + +/* + *------------------------------------------------------------------ + * + * suppress -- + * + * Decide if any of these hints have bounced around + * network too much to be worth looking at (mainly + * we want to suppress loops.) In prinicple, + * the algorithm guarantees that loops cannot occur, + * but best to be safe. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in updateA to mark them as "ignore." + * + *-----------------------------------------------4.1.1998------------- + */ +static void +suppress(HintCacheUpdate * updateA, int nupdates) +{ +#ifdef NOTYET + /* Need to fill this in */ + int iupdate; + + for (iupdate = 0; iupdate < nupdates; iupdate++) { + if (stoppable update) { + updateA[iupdate].action = HC_Ignore; + } + } +#endif + + return; +} + +/* + *------------------------------------------------------------------ + * + * updateHierarchy -- + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in update array to be "HC_Ignore." + * + *------------------------------------------------4.1.1998------------ + */ +static void +updateHierarchy(HintCacheUpdate * updatesA, int nupdates, struct sockaddr_in *source) +{ + int iupdate; + int parentScolded = 0; + + for (iupdate = 0; iupdate < nupdates; iupdate++) { + switch (updatesA[iupdate].action) { + case HC_InformToChild: + case HC_InvalToChild: + if (!HCHier_CheckIfParent(updatesA[iupdate].entry.key, source)) { + if (!parentScolded) { + scoldParent(source); + parentScolded = 1; + } + updatesA[iupdate].action = HC_Ignore; + } + break; + + case HC_InformToParent: + case HC_InvalToParent: +#if 1 /* XXX! - disabling parent&child lists */ + if (!hintCacheHier_CheckIfChild(source)) { + hintCacheHier_AddChild(source); + } +#endif + break; + + case HC_NotChild: + hintCacheHier_RemoveChild(source); + updatesA[iupdate].action = HC_Ignore; + break; + + + default: + /* + * Other messages don't affect hierarchy. Ignore them here. + */ + break; + } + } +} + +/* + *------------------------------------------------------------------ + * + * scoldParent -- + * + * Tell parent "I am not child". Need to use + * our own private HintCacheNet queue since all of the + * other queues are associated with the hierarchy + * and this message is to tell someone they + * are *not* in the hierarchy. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.2.1998------------ + */ +static void +scoldParent(struct sockaddr_in *parent) +{ + static int initialized = 0; + static HintCacheNet netBuf; + static HintCacheEntry dummyEntry; + static URLKey dummyKey; + + debug(HCNET_DEBUG, 7) ("In scoldParent %s\n", inet_ntoa(parent->sin_addr)); + + if (!initialized) { + hintCacheNetInit(&netBuf); + URLKey_Init(&dummyKey, NULL); + hintCacheEntry_Init(&dummyEntry, dummyKey, + &Config.Sockaddr.http->s, squid_curtime); + initialized = 1; + } + + hintCacheNetEnqueue(&netBuf, HC_NotChild, &dummyEntry, 1); + hintCacheNetComplete(&netBuf); + hintCacheNetSendTo(&netBuf, parent); + hintCacheNetDone(&netBuf); + return; +} Index: squid/src/HintCacheNodes.c diff -u /dev/null squid/src/HintCacheNodes.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCacheNodes.c Mon May 20 19:46:41 2002 @@ -0,0 +1,970 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 88 List of known caches. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCNodelist --- + * The nodelist keeps a list of all nodes in the hierarchy whether they + * are alive or dead. It uses a flooding algorithm for this (see + * ../notes.3.17.1998). As part of this flooding algorithm, it learns + * a hopcount to other nodes. We tell squid_db this hopcount as an + * initial *rough* estimate of distance between nodes. + * + * The flooding algorithm needs as input a list of "neighbors". The lists + * of neighbors for all nodes MUST overlap. The lists of neighbors SHOULD + * include only nearby neighbors (so that the hopcounts are correct). + * It uses the squid static hierarchy (see neighbors.c e.g. getFirstPeer() + * etc) for this initial list. + *------------------------------------------------------------------ + */ +#include "squid.h" + +/* + * Mike Dahlin's interface comments from HCNodelist.h: + * + * Out-calls: These internal routines are where you should place + * outcalls for being notified of important events: + * + * static void HCNodelist_OutcallHops _PARAMS((struct sockaddr_in sin, + * int hops)); + * + * e.g. The nodelist promises to tell squid_db whenever it learns a new + * distance to a node. ?? The nodelist promises to tell Plaxton + * when the distance to a node changes?? + * + * static void HCNodelist_OutcallJoin() _PARAMS((struct sockaddr_in sin)); + * e.g. The nodelist promises to tell Plaxton when a new node joins. + * + * static void hintCacheNodelist_OutcallLeave() _PARAMS((struct sockaddr_in sin)); + * The nodelist promises to tell Plaxton when a node leaves. + */ + +#define HCNODES_DEBUG 88 + +typedef struct HierNodeElem +{ + dlink_node links; + struct sockaddr_in sin; + int action; /* HC_Join or HC_Leave */ + long long timestamp_ns; /* time of action */ +} +HierNodeElem; + +static dlink_list nodes; +static int myStatus = HC_Leave; + +static void HierNodeElem_Init _PARAMS((HierNodeElem *, struct sockaddr_in *, + int action, long long timestamp_ns)); + +static HierNodeElem *nodeFind(struct sockaddr_in *sin); +static long long currentTimeNS(); +static void floodEvent(int action, struct sockaddr_in *source, + long long timeNS, int hopcount); + +static void hintCacheNodelistOutcallHops(struct sockaddr_in *sin, + int hops, long long timeNS); +static void hintCacheNodelistOutcallJoin(struct sockaddr_in *sin, + int hops, long long timeNS); +static void hintCacheNodelistOutcallLeave(struct sockaddr_in *sin, + int hops, long long timeNS); + +static void printList(); + + +static void +HierNodeElem_Init(HierNodeElem * e, struct sockaddr_in *sin, int action, + long long timestamp_ns) +{ + assert(action == HC_Join || action == HC_Leave); + List_InitElement(&e->links); + e->sin = *sin; + e->action = action; + e->timestamp_ns = timestamp_ns; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeList_Init -- + * + * Constructor. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Initialize nodelist to empty list. + * + *----------------------------------------------3.31.1998------------- + */ +void +hintCacheNodelistInit(void) +{ + nodes.head = nodes.tail = 0; +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListDestroy -- + * + * Deallocate all elements in list + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------3.31.1998------- + */ +void +hintCacheNodelist_Destroy(void) +{ + dlink_node *item; + + while (nodes.head) { + item = nodes.head; + dlinkDelete(item, &nodes); + xfree(item); + } +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListLocalJoin -- + * + * Do a local join. This tells the algorithm + * to flood "join" messages to the neighbors. + * + * Arguments: + * struct sockaddr_in myId -- my ip address + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.1.1998---- + */ +void +hintCacheNodelistLocalJoin(void) +{ + struct sockaddr_in *myId; + int hopcount; + long long timeNS; +#if 0 + HintCacheEntry hcEntry; + HintCacheUpdate update; + URLKey key; + int nbpl; + int ii; +#endif + + myStatus = HC_Join; + + myId = &Config.Sockaddr.http->s; + timeNS = currentTimeNS(); + hopcount = 1; + floodEvent(HC_Join, myId, timeNS, hopcount); + +#if 0 + /* "Priming" code */ + if (parentOutgoingA) { + nbpl = (hintCachePlax_bucketsPerLevel > 0) ? hintCachePlax_bucketsPerLevel : 256; + for (ii = 0; ii < nbpl; ii++) { + key.key = ii; + hintCacheEntry_Init(&hcEntry, key, &Config.Sockaddr.http->s); + hintCacheUpdate_Init(&update, HC_InvalToParent, &hcEntry, 1); + hcprop_handleInvalToParent(&update, 1); + } + } +#endif +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListLocalLeave -- + * + * Do a local leave. This tells the algorithm + * to flood "leave" messages to the neighbors. + * + * Arguments: + * struct sockaddr_in myId -- my ip address + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.1.1998---- + */ +void +hintCacheNodelistLocalLeave(void) +{ + struct sockaddr_in *myId; + int hopcount; + long long timeNS; + + myStatus = HC_Leave; + myId = &Config.Sockaddr.http->s; + timeNS = currentTimeNS(); + hopcount = 1; + floodEvent(HC_Leave, myId, timeNS, hopcount); +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistgetMyStatus -- + * + * Am I currently in or out? + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.1.1998-------- + */ +int +hintCacheNodelistmyStatus(void) +{ + return myStatus; +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistNetJoin -- + * + * Process a "join" received from the network. + * If this is a new node, a new action for a node, + * or a current action with a shorter distance, + * proceed with the join and propagate message + * to neighbors. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Allocates and adds an element to the list; calls + * OutcallJoin(). + * + *------------------------------------------------------7.19.1998---- + */ +void +hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long joinTimeNS) +{ + HierNodeElem *h, *oldCopy; + int oldHops; + int foundOldJoin = 0; + int joinIsNewer; + + assert(sin); + /* Ignore if it's already on list and either (1) a newer record + * or (2) a current record and at least as close as this + * update. Also ignore if it is me! + * For simplicity, rather than update a record in place, remove + * it and add a new record to front of list. This should be better + * for performance, too, since we expect to get a burst of + * notifications from all neighbors, so put record at front of list. + */ + if (!SINCMP(sin, &Config.Sockaddr.http->s)) { + return; + } + oldCopy = nodeFind(sin); + if (oldCopy != NULL) { + if (oldCopy->timestamp_ns > joinTimeNS) { + /* We got a stale message; ignore it */ + return; + } else if (oldCopy->action != HC_Join + && oldCopy->timestamp_ns < joinTimeNS) { + /* Join supercedes an old HC_Leave */ + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + /* Fall through and add this join to nodelist */ + } else { + assert(oldCopy->action == HC_Join); + foundOldJoin = 1; + assert(oldCopy->timestamp_ns <= joinTimeNS); + joinIsNewer = (oldCopy->timestamp_ns < joinTimeNS); + oldHops = netdbHintHops(sin->sin_addr); + + + if (oldHops > hops) { + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + /* Fall through and add this join to nodelist and flood */ + } else if (joinIsNewer) { + /* + * Join is newer but not closer. Propagate to neighbors + * but no need to do anything locally beyond updating + * the timestamp. + */ + oldCopy->timestamp_ns = joinTimeNS; + floodEvent(HC_Join, sin, joinTimeNS, hops + 1); + return; + } + } + } + /* + * Only get here if new join supercedes and old join removed or + * nonexistant. Do the join and flood it to neighbors. + */ + assert(!nodeFind(sin)); + + h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem)); + HierNodeElem_Init(h, sin, HC_Join, joinTimeNS); + dlinkAdd(h, &h->links, &nodes); + + /* + * Now tell everyone else (locally and network) about + * the new addition or new distance + */ + floodEvent(HC_Join, sin, joinTimeNS, hops + 1); + if (foundOldJoin) { + HintCacheNodelistOutcallHops(sin, hops, joinTimeNS); + } else { + hintCacheNodelistOutcallJoin(sin, hops, joinTimeNS); + } + + if (!foundOldJoin) { + debug(HCNODES_DEBUG, 2) + ("hintCacheNodelist::NetJoin() adds %d.%d.%d.%d; list is: \n", + (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0)); + printList(); + debug(HCNODES_DEBUG, 2) ("\n"); + } + +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistNetLeave -- + * + * Process a notification that a node has left the system + * + * We keep "departed" nodes on nodelist with a "leave" flag + * set so we know when to stop propagating messages. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------7.19.1998-------------- + */ +void +hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long leaveTimeNS) +{ + HierNodeElem *h, *oldCopy; + int foundOldLeave = 0; + + assert(sin); + + /* Ignore if it's already on list and a newer record. + * For simplicity, rather than update a record in place, remove + * it and add a new record to front of list. This should be better + * for performance, too, since we expect to get a burst of + * notifications from all neighbors, so put record at front of list. + */ + oldCopy = nodeFind(sin); + if (oldCopy) { + if (oldCopy->action == HC_Leave) { + foundOldLeave = 1; + } + if (oldCopy->timestamp_ns < leaveTimeNS) { + dlinkDelete(&oldCopy->links, &nodes); + xfree(oldCopy); + } else { + /* + * old copy is actually newer than this update. Ignore this + * update. + */ + return; + } + } + /* + * Only get here if new leave supercedes old record removed or + * nonexistant + */ + assert(!nodeFind(sin)); + + h = (HierNodeElem *) xmalloc(sizeof(HierNodeElem)); + HierNodeElem_Init(h, sin, HC_Leave, leaveTimeNS); + dlinkAdd(h, &h->links, &nodes); + + /* + * Now tell everyone else (locally and network) about + * the new addition or new distance + */ + floodEvent(HC_Leave, sin, leaveTimeNS, hops + 1); + if (!foundOldLeave) { + HCNodelist_OutcallLeave(sin, hops, leaveTimeNS); + } + + if (!foundOldLeave) { + debug(HCNODES_DEBUG, 4) + ("HCNodelist::NetLeave() removes %d.%d.%d.%d; list is: \n", + (unsigned char) ((sin->sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((sin->sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((sin->sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((sin->sin_addr.s_addr & 0x000000FF) >> 0)); + printList(); + debug(HCNODES_DEBUG, 4) ("\n"); + } +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelist_OutcallHops -- + * + * This function gets called whenever the number of hops + * to a node *changes* due to network updates. This + * is a good place to put function calls to modules that + * care to hear about such things. + * + * 1) netdb + * 2) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------7.19.1998----- + */ +static void +hintCacheNodelistOutcallHops(struct sockaddr_in *sin, int hops, long long timeNS) +{ + char name[16]; + + /* + * Tell netdb + */ + strcpy(name, inet_ntoa(sin->sin_addr)); + if (!netdbHintHops(sin->sin_addr)) { + netdbAdd(sin->sin_addr, name); + } + netdbUpdateHintHops(sin->sin_addr, hops); + + /* + * Tell plaxton algorithm + */ + hintCachePlax_changeDistance(sin); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistOutcallJoin -- + * + * This function gets called whenever a node joins the + * sytsem. + * This is a good place to put function calls to modules that + * care to hear about such things. + * + * Right now, 3 people care: + * 1) netdb + * 2) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------7.19.1998----------- + */ +static void +hintCacheNodelistOutcallJoin(struct sockaddr_in *sin, int hops, long long timeNS) +{ + char name[16]; + + /* + * Tell netdb + */ + strcpy(name, inet_ntoa(sin->sin_addr)); + netdbAdd(sin->sin_addr, name); + netdbUpdateHintHops(sin->sin_addr, hops); + + /* + * Tell plaxton algorithm + */ + hintCachePlax_addNode(sin); +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistOutcallLeave -- + * + * This function gets called whenever a node leaves the + * sytsem. + * This is a good place to put function calls to modules that + * care to hear about such things. + * + * 1) plaxton dynamic hierarchy algorithm + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------7.19.1998---------- + */ +static void +hintCacheNodelistOutcallLeave(struct sockaddr_in *sin, int hops, long long timeNS) +{ + /* + * Tell plaxton algorithm + */ + hintCachePlax_removeNode(sin); +} + + +/* + *------------------------------------------------------------------ + * + * nodeFind -- + * + * Find node with matching address. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static HierNodeElem * +nodeFind(struct sockaddr_in *sin) +{ + HierNodeElem *e; + dlink_node *item; + + for (item = nodes.head; item; item = item->next) { + e = (HierNodeElem *) item; + if (!SINCMP(&e->sin, sin)) { + return (e); + } + } + return (NULL); +} + +/* + *------------------------------------------------------------------ + * + * floodEvent -- + * + * Send the notification to our neighbors. + * + * Arguments: + * int action HC_Join or HC_Leave + * struct sockaddr_in *source -- the subject of the action + * long long timeNS -- the time of the action (used for + * ordering events and removing duplicates) + * int hopcount -- how many hops has this event seen? + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------3.31.1998-------- + */ +static void +floodEvent(int action, struct sockaddr_in *source, long long timeNS, + int hopcount) +{ +#ifdef USE_DYNAMIC_HIERARCHY + HintCacheEntry entry; + peer *p; + URLKey hackURLKey; + struct sockaddr_in dest; + + assert(action == HC_Join || action == HC_Leave); + + if (neighborsOutgoing == NULL) { + return; + } + + hackURLKey.key = timeNS; /* XXX Update should be a union XXX */ + + hintCacheEntry_Init(&entry, hackURLKey, source); + hintCacheNet_Enqueue(neighborsOutgoing, action, &entry, hopcount); +#if 1 + hintCacheNet_Complete(neighborsOutgoing); + + for (p = getFirstPeer(); p; p = getNextPeer(p)) { + if (p->in_addr.sin_addr.s_addr == 0) { + debug(HCNODES_DEBUG, 4) + ("hintCacheNodelist warning: peer %s addr not set\n", p->host); + continue; + } + dest.sin_family = AF_INET; + dest.sin_addr = p->in_addr.sin_addr; + dest.sin_port = p->http_port; + hintCacheNet_SendTo(neighborsOutgoing, &dest); + } + + hintCacheNet_Done(neighborsOutgoing); +#endif +#endif /* USE_DYNAMIC_HIERARCHY */ +} + + + +/* + *------------------------------------------------------------------ + * + * hintCacheNodeListIterXXX -- + * + * Used for iterating through all addresses on list. + * + * for(hintCacheNodeListIterStart(&iter); + * hintCacheNodeListIterCheck(&iter); + * hintCacheNodeListIterNext(&iter)){ + * valid = hintCacheNOdeListIterGetAddr(&iter, &addr); + * } + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Note -- only itereates through "joined" elements; + * Skip the shadow elements representing nodes that + * have left. + * + * Warning -- iterator is pointer into element on list. + * If list changing during iteration, could get confused. + * + *------------------------------------------------------------------ + */ +void +hintCacheNodeListIterStart(HintCacheNodeListIter iter) +{ + iter = (HintCacheNodeListIter) nodes.head; +} + +int +hintCacheNodeList_IterCheck(HintCacheNodeListIter iter) +{ + dlink_node *links = iter; + return (links->next != 0); +} + +void +hintCacheNodeList_IterNext(HintCacheNodeListIter iter) +{ + HierNodeElem *elem; + + if (iter->next == 0) { + return; + } + + while (1) { + iter = iter->next; + /* + * Skip non-HC_Join elements by keeping going in that case. + */ + if (iter->next == 0) { + return; + } + elem = iter->data; + if (elem->action == HC_Join) { + return; + } + } + +} + +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistIterGetAddr -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter, struct sockaddr_in *ret) +{ + HierNodeElem *elem; + elem = iter->data; + *ret = elem->sin; + if (elem->action == HC_Join) { + return 1; + } + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * currentTimeNS -- + * + * Return the current time in nanoseconds since Jan 1, 1970. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static long long +currentTimeNS() +{ + static const long long NS_PER_SEC = 1000000000; + static const long long NS_PER_USEC = 1000; + int error; + struct timeval time; + long long ret; + + error = gettimeofday(&time, NULL); + assert(error != -1); + ret = NS_PER_SEC * (long long) time.tv_sec + + NS_PER_USEC * (long long) time.tv_usec; + return ret; +} + +/* + *------------------------------------------------------------------ + * + * printList -- + * + * Print the current list of nodes to stdout. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + + *------------------------------------------------------------------ + */ +static void +printList() +{ + HintCacheNodeListIter iter; + struct sockaddr_in nodeAddr; + int valid; + + for (hintCacheNodeListIterStart(iter); + hintCacheNodeListIterCheck(iter); hintCacheNodeListIterNext(&iter)) { + valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr); + if (valid) { + debug(HCNODES_DEBUG, 2) + ("\t%d.%d.%d.%d\n", + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0xFF000000) >> 24), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x00FF0000) >> 16), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x0000FF00) >> 8), + (unsigned char) ((nodeAddr.sin_addr.s_addr & 0x000000FF) >> 0)); + } + } +} + + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * hintCacheNodelistSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheNodelistSelfTest(void) +{ + struct sockaddr_in n0, n1, n2; + HintCacheNodeListIter iter; + struct sockaddr_in nodeAddr; + int nhops; + int valid; + int found = 0; + + printf("HintCacheNodelistSelfTest..."); + n0.sin_addr.s_addr = 0x90536F00; + n0.sin_port = 0; + n1.sin_addr.s_addr = 0x91536F01; + n1.sin_port = 1; + n2.sin_addr.s_addr = 0x92536F02; + n2.sin_port = 2; + + hintCacheNodelistInit(); + hintCachePlax_Init(8); + + assert(neighborsOutgoing == NULL); + neighborsOutgoing = (HintCacheNet *) xmalloc(sizeof(HintCacheNet)); + assert(neighborsOutgoing); + hintCacheNet_Init(neighborsOutgoing); + hintCacheNet_SetTestMode(neighborsOutgoing); + + + /* + * How to test if this really works? For now look at how many + * outgoing messages were enqueued. + */ + hintCacheNodelistLocalJoin(); + hintCacheNodelistLocalLeave(); + assert(hintCacheNet_GetTestCount(neighborsOutgoing) == 2); + + /* + * Expected final state: + * n0 JOIN dist = 12 + * n1 LEAVE XXX + * n2 JOIN dist=20 + */ + hintCacheNodelistNetJoin(&n0, 10, 42); + hintCacheNodelistNetJoin(&n2, 20, 42); + hintCacheNodelistNetJoin(&n0, 13, 43); + hintCacheNodelistNetJoin(&n1, 20, 42); + hintCacheNodelistNetJoin(&n2, 20, 100); + hintCacheNodelistNetJoin(&n0, 9, 42); + hintCacheNodelistNetJoin(&n0, 12, 43); + hintCacheNodelistNetJoin(&n2, 20, 42); + hintCacheNodelistNetLeave(&n1, 999, 43); + hintCacheNodelistNetJoin(&n1, 19, 42); + + for (hintCacheNodeListIterStart(&iter); + hintCacheNodeListIterCheck(iter); hintCacheNodeList_IterNext(&iter)) { + valid = hintCacheNodeListIterGetAddr(iter, &nodeAddr); + if (valid) { + nhops = netdbHintHops(nodeAddr.sin_addr); + if (nodeAddr.sin_addr.s_addr == n0.sin_addr.s_addr) { + found++; + assert(nhops == 12); + } + if (nodeAddr.sin_addr.s_addr == n2.sin_addr.s_addr) { + found++; + assert(nhops = 20); + } + if (nodeAddr.sin_addr.s_addr == n1.sin_addr.s_addr) { + assert(0); + } + } + } + assert(found == 2); + + hintCacheNodelistDestroy(); + hintCachePlaxDestroy(); + + hintCacheNetDestroy(neighborsOutgoing); + free(neighborsOutgoing); + neighborsOutgoing = NULL; + + printf("..OK\n"); + +} + +#endif /* DOTEST */ Index: squid/src/HintCachePrim.c diff -u /dev/null squid/src/HintCachePrim.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/HintCachePrim.c Mon May 20 19:46:42 2002 @@ -0,0 +1,404 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 89 List of known caches. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCPrimitives.h --- Primitive types for hint cache. + *------------------------------------------------------------------ + */ +#include "squid.h" +#include + + +const URLKey INVALID_URL_KEY = { 0 }; + +static HintCacheKey calculateStupidKey(char *url); +static void makeLowerCase(char *url); + +const static int useMD5 = 1; + + +/* + *------------------------------------------------------------------ + * + * URLKey -- + * + * The first 64 bits of the 128-bit Squid/Cache Digest URL key. + */ + + + +/* + * Make lower case, but stop at third '/' (e.g., after the hostname). + */ +static void +makeLowerCase(char *url) +{ + int len, ii; + int slashCount = 0; + + assert(url); + len = strlen(url); + for (ii = 0; ii < len; ii++) { + /* + * Alignment. + */ + if (url[ii] == '/') { + slashCount++; + if (slashCount == 3) { + return; + } + } + url[ii] = tolower(url[ii]); + } +} + + +/* functional encapsulation of the ever-popular macro of the + same name. Needed for hash table. */ +int +hintCacheURLKeyCompare(URLKey *u1, URLKey *u2) +{ + return(URLKEY_COMPARE(*u1, *u2)); +} + +/* + * Retrieve entry using hint_table. + * The hint_table keeps a pointer to the hchash part of th + * StoreEntry, so we apply the appropriate offset to + * retrieve the StoreEntry itself. + */ +StoreEntry * +hintCacheStoreGet(URLKey urlkey) +{ + hash_link *hchash; + StoreEntry *entry; + int hchoff; + + hchash = (hash_link *) hash_lookup(store_table, &urlkey); + hchoff = (u_char *) &entry->hchash - (u_char *) entry; + entry = (StoreEntry *) ((u_char *) hchash - hchoff); + return(entry); +} + + +void +hintCacheNetURLKeyNetInit(URLKeyNet * mungedKey, URLKey * key) +{ + mungedKey->mungedKey = hintCacheEndian_llMachineToNet(key->key); +} + +void +hintCacheNetURLKeyLocalFormat(URLKeyNet * mungedKey, URLKey * key) +{ + key->key = hintCacheEndian_llNetToMachine(mungedKey->mungedKey); +} + + + +/* + *------------------------------------------------------------------ + * + * NodeKey -- + * + * A pair (plus stuff to + * put it on a list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.9.1998-------- + */ +void +hintCacheNodeKeyInit(NodeKey * k, const struct sockaddr_in *addrP) +{ + assert(k); + assert(addrP); + + k->links.data = k; + k->links.next = k->links.prev = 0; + k->key = hintCacheNodeKeyKey(addrP); + k->addr = *addrP; +} + +int +hintCacheNodeKeyCompare(const NodeKey * k1, const NodeKey * k2) +{ + assert(k1); + assert(k2); + if (k1->key != k2->key) { + return 1; + } + return 0; +} + +struct sockaddr_in +hintCacheNodeKeyGetAddr(const NodeKey * k) +{ + assert(k); + return k->addr; +} + +HintCacheKey +hintCacheNodeKeyKey(const struct sockaddr_in * addrP) +{ + HintCacheKey k; + char *name; + + name = inet_ntoa(addrP->sin_addr); + k = *(HintCacheKey *) storeKeyPublic(name, METHOD_PUT); + return k; +} + + +/* + *------------------------------------------------------------------ + * + * hintCacheEntry -- + * + * A structure including a pair. Generally + * points to the nearest copy of the specified url. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheEntryInit(HintCacheEntry * entry, URLKey key, struct sockaddr_in *saddr, + unsigned int mtime) +{ + entry->key = key; + entry->ipaddr = saddr->sin_addr; + entry->port = saddr->sin_port; + entry->pad = 0; + entry->mtime = mtime; +} + +int +hintCacheEntryCompare(HintCacheEntry * e1, HintCacheEntry * e2) +{ + /* + * If you add a field, you must change this code. + */ + if (URLKEY_COMPARE(e1->key, e2->key)) { + return 1; + } + + if (e1->ipaddr.s_addr != e2->ipaddr.s_addr) + return 1; + + if (e1->port != e2->port) + return 1; + + if (e1->mtime != e2->mtime) + return 1; + + return 0; +} + +void +hintCacheNetEntryInit(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry) +{ + /* + * If you add a field, you must change this code. + */ + URLKeyNetInit(&mungedEntry->mungedKey, &entry->key); +/* mungedEntry->mungedIpaddr.s_addr = htonl(entry->ipaddr.s_addr);*/ + mungedEntry->mungedIpaddr.s_addr = entry->ipaddr.s_addr; + mungedEntry->mungedPort = htons(entry->port); + mungedEntry->mungedMtime = htonl(entry->mtime); +} + +void +hintCacheEntryLocalFormatNet(HintCacheEntryNet * mungedEntry, HintCacheEntry * entry) +{ + /* + * If you add a field, you must change this code. + */ + URLKeyLocalFormatNet(&mungedEntry->mungedKey, &entry->key); +/* entry->ipaddr.s_addr = ntohl(mungedEntry->mungedIpaddr.s_addr);*/ + entry->ipaddr.s_addr = mungedEntry->mungedIpaddr.s_addr; + entry->port = ntohs(mungedEntry->mungedPort); + entry->mtime = htonl(mungedEntry->mungedMtime); +} + + +/* + *------------------------------------------------------------------ + * + * HCUpdate -- + * + * An update is a HintCacheEntry and an action. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +hintCacheUpdateInit(HintCacheUpdate * u, int action, HintCacheEntry * entry, int hopcount) +{ + u->action = action; + u->hopcount = hopcount; + u->UNUSED = 0; /* remove this field sometime */ + u->entry = *entry; +} + +void +hintCacheUpdateSelfTest() +{ + HintCacheUpdate update; + HintCacheUpdateNet netupd; + + /* HintCacheUpdate must be at least this min size */ + assert(sizeof(HintCacheUpdate) >= HCU_MINLEN); + + /* Test that some field in update has expected offset */ + assert((char *) &update.entry - (char *) &update == 8); + assert((char *) &netupd.mungedEntry - (char *) &netupd == 8); + + /* Make sure net version of struct stays in sync. */ + assert(sizeof(HintCacheUpdate) == sizeof(HintCacheUpdateNet)); +} + +void +hintCacheUpdateInitNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update) +{ + /* No need for htonl on action, hopcount, or len - they are single bytes. */ + mupdate->mungedAction = update->action; + mupdate->mungedUNUSED = update->UNUSED; /* remove this field sometime */ + mupdate->mungedHopcount = update->hopcount; + mupdate->mungedPad1 = -1; + mupdate->mungedPad2 = -1; +/* mupdate->mungedCchange = htonl(update->cchange); XXX - NOTYET */ + + hintCacheEntryInitNet(&mupdate->mungedEntry, &update->entry); +} + + +void +hintCacheUpdateLocalFormatNet(HintCacheUpdateNet * mupdate, HintCacheUpdate * update) +{ + /* No need for htonl on action or len - they are single bytes. */ + update->action = mupdate->mungedAction; + update->UNUSED = mupdate->mungedUNUSED;; + update->hopcount = mupdate->mungedHopcount; +/* update->cchange = ntohl(mupdate->mungedCchange); XXX - NOTYET */ + + hintCacheEntryLocalFormatNet(&mupdate->mungedEntry, &update->entry); +} + +int +hintCacheUpdateCompare(HintCacheUpdate * u1, HintCacheUpdate * u2) +{ + if ((u1->action != u2->action) + || (u1->hopcount != u2->hopcount) + || (hintCacheEntry_Compare(&u1->entry, &u2->entry))) { + return 1; + } + return 0; +} + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * primitivesSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +void +primitivesSelfTest() +{ + + URLKey urlKey, urlKey2; + URLKeyNet netUrlKey; + char url[128]; + HintCachEntry hcEntry, hcEntry2; + HintCacheEntry netHintCacheEntry; + HintCacheUpdate hcUpdate, hcUpdate2; + HintCacheUpdateNet netHintCacheUpdate; + struct sockaddr_in saddr = { AF_INET, 0, {{{0, 0, 0, 0}}} }; + + printf("primitivesSelfTest().."); + + sprintf(url, "http://www.cs.Utexas.edu"); + hintCacheURLKey_Init(&urlKey, url); + Net_URLKey_Init(&netUrlKey, &urlKey); + URLKeyLocalFormatNet(&netUrlKey, &urlKey2); + assert(!URLKEY_COMPARE(urlKey, urlKey2)); + + hintCacheEntryInit(&hcEntry, urlKey, &saddr); + hintCacheEntryInitNet(&netHintCacheEntry, &hcEntry); + hintCacheEntryLocalFormatNet(&netHintCacheEntry, &hcEntry2); + assert(!hintCacheEntryCompare(&hcEntry, &hcEntry2)); + + hintCacheUpdateInit(&hcUpdate, HC_InvalToChild, &hcEntry, 1); + hintCacheUpdate_selfTest(); + hintCacheUpdateInitNet(&netHintCacheUpdate, &hcUpdate); + hintCacheUpdateLocalFormatNet(&netHintCacheUpdate, &hcUpdate2); + assert(!HintCacheUpdate_Compare(&hcUpdate, &hcUpdate2)); + + printf(".OK\n"); +} +#endif /* DOTEST */ Index: squid/src/Makefile.am diff -u squid/src/Makefile.am:1.24 squid/src/Makefile.am:1.8.2.5 --- squid/src/Makefile.am:1.24 Sun Sep 1 09:30:40 2002 +++ squid/src/Makefile.am Tue Sep 3 10:41:32 2002 @@ -52,6 +52,32 @@ SSLSOURCE = endif +if ENABLE_HINTS +HINTSOURCE = \ + HintCache.c \ + HintCacheDisk.c \ + HintCacheEndian.c \ + HintCacheHier.c \ + HintCacheNet.c \ + HintCacheNodes.c \ + HintCachePrim.c \ + HintCacheProp.c +else +HINTSOURCE= +endif + +if ENABLE_PLAXTON +PLAXSOURCE = Plaxton.c +else +PLAXSOURCE = +endif + +if ENABLE_ICP_DATA +ICPDATASOURCE = icp_data.c +else +ICPDATASOURCE = +endif + if ENABLE_WIN32SPECIFIC WIN32SOURCE = win32.c else @@ -74,6 +100,7 @@ squid bin_PROGRAMS = \ + webpush \ squidclient libexec_PROGRAMS = \ @@ -122,6 +149,7 @@ defines.h \ $(DELAY_POOL_SOURCE) \ disk.c \ + dist.c \ $(DNSSOURCE) \ enums.h \ errorpage.c \ @@ -136,6 +164,7 @@ globals.h \ gopher.c \ helper.c \ + $(HINTSOURCE) \ $(HTCPSOURCE) \ http.c \ HttpStatusLine.c \ @@ -151,6 +180,7 @@ icmp.c \ icp_v2.c \ icp_v3.c \ + $(ICPDATASOURCE) \ ident.c \ internal.c \ ipc.c \ @@ -168,7 +198,9 @@ pconn.c \ peer_digest.c \ peer_select.c \ + $(PLAXSOURCE) \ protos.h \ + put.c \ redirect.c \ referer.c \ refresh.c \ @@ -283,6 +315,7 @@ DEFAULT_ICON_DIR = $(datadir)/icons DEFAULT_ERROR_DIR = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@ DEFAULT_MIB_PATH = $(datadir)/mib.txt +DEFAULT_HINT_FILE = $(DEFAULT_SWAP_DIR)/hints DEFAULT_HOSTS = @OPT_DEFAULT_HOSTS@ DEFS = @DEFS@ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" @@ -333,6 +366,7 @@ s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g;\ s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g;\ s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g;\ + s%@DEFAULT_HINT_FILE@%$(DEFAULT_HINT_FILE)%g;\ s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;\ s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g;"\ < $(srcdir)/cf.data.pre >$@ Index: squid/src/Plaxton.c diff -u /dev/null squid/src/Plaxton.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:38 2004 +++ squid/src/Plaxton.c Mon May 20 19:46:42 2002 @@ -0,0 +1,2440 @@ +/* + * $Date: 2004/08/17 20:55:13 $ $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 91 Greg Plaxton's per-object hierarchy. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * Plaxton.c --- Dynamic algorithm via plaxton's algorithm. + *------------------------------------------------------------------ + */ + +/* + * Plaxton.c interface notes, from Mike Dahlin's comments in HCPlax.h: + * + * Each children queue holds messages that should go to a set of + * "equivalent" children (eg. the children at some level of the + * hierarchy.) There are HCHPlax_NChildrenQs() such queues; + * num = HCPlax_GetChildAddrs(q, arraypointer) allocates + * an array of addresses for a particular queue and returns + * the number of children. + * The rule is simple -- when I send a message to children about + * an object, I send it to all children who match that object's + * key in fewer bits than I do. + * + * Each parent queue holds messages that should go to one parent. + * In general, we may have different parents for different objects. + * So, enqueue messages for an object in the queue + * HCPlax_ParentQIndex(URLKey). + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + */ + +#include "squid.h" + + +#define HCPLAX_DEBUG 91 + +/* + * Array [BITS_PER_BYTE * sizeof(HintCacheNodeKeyKey) + 1] of dlink_nodes + */ +#define BITS_PER_BYTE 8 +#define BITS_PER_KEY (8 * sizeof(HintCacheKey)) + +static HintCacheKey myNodeKey; + +static int initialized = 0; + +/* + * For keeping track of children + */ +static int nChildLists = -9999; +static dlink_list *childrenListA; +static int *childrenCountA = NULL; /* Entry i is the number of children + * that match in i bits. */ +static int childrenCountTot = 0; + +/* + * For keeping track of parents + */ +int Plaxton_bucketsPerLevel = -999; +static int nParentLevels = -999; +static int bitsPerLevel = -999; +static int maxParentBucket = -9999; +/* + * parentListA is an array [nParentLevels][Plaxton_bucketsPerLevel] + * where entry k = l*bitsPerLevel + i (0 <= i < 2^bitsPerLevel) + * contains a list of all known nodes whose node key matches + * the local node key in the lowest l*bitsPerLevel bits + * and whose next bitsPerLevel bits have the same bit pattern + * as i + * For example, with bitsPerLevel = 2, if our local node key + * were 010110, a node with key 111010 would belong in level 1 + * (since the bottom two bits match us but the next two bits dont + * in entry 10), so node 111010 would go into bucket + * 1*Plaxton_bucketsPerLevel + 10 = 4 + 2 = 6. + * Maintain the invariant that the entries in each bucket are sorted + * by their distance from me with the closest node always + * at the head of its list. + */ +static dlink_list *parentListA = NULL; +/* + * Special case of parent finding when I match in as many bits + * as anyone. In case of a tie for root, + * we all need to agree on whom among us is the root. We need + * to do so in a way that avoids loops (and hopefully which + * gets everyone to agree on the same root.) Solution: if + * an object matches me in k bits and I know of no node + * that matches the object in more than k bits, choose as + * the root for that object, the node that matches the + * object (and me) in k bits and which has the highest + * known NodeKey. + * + * highestMatchA is an array [BITS_PER_KEY] where entry k + * contains a list of all nodes that match me in at least + * the bottom k bits. The lists all include me. The lists + * are sorted by the integer value of the key with the + * largest value at the head of the list. + */ +static dlink_list *highestMatchA = NULL; + +static int normalParentIndex(int bucket); +static int fullMatchIndex(HintCacheKey k); +static int firstLevelBucketForMatch(int matchBits); +static int highestMatchIndex(int matchBits); +static void childAdd _PARAMS((HintCacheNodeKey * key)); +static HintCacheNodeKey *childFind _PARAMS((HintCacheNodeKey * key)); +static void freeList(dlink_list * list); +static void addNodeParentList(struct sockaddr_in *addNode); +static void removeNodeParentList(struct sockaddr_in *goneNode); +static void changeDistanceParentList(struct sockaddr_in *changeDistNode); +static int parentListIndex(HintCacheNodeKey * n); +static void addNodeHighestMatch(struct sockaddr_in *addNode); +static void matchInsert(dlink_list *l, struct sockaddr_in *a); +static void removeNodeHighestMatch(struct sockaddr_in *goneNode); +static void matchRemove(dlink_list *l, struct sockaddr_in *a); +static int scanForParentMatch(int maxTry, int minTry, const URLKey * key, + int *parentIndexRet, int *amIRootRet); +static HintCacheKey makeMatchKey(const URLKey * key, int matchBits, + int permuteVal); + +#ifdef DOTEST +static void selfTestChildren(); +static int selfTestFindAddr(int addr, struct sockaddr_in *childrenA, + int childCount); +static void selfTestParents(); +static void testParentsBinaryTree(void); +static void testParentsMultiRootCase(void); +static void stressTestParents(void); +static void testParentsInternals(void); +static void testParentsInternals2(void); +static void testMakeMatchKey(void); +#endif /* DOTEST */ + +/* + *------------------------------------------------------------------ + * + * plaxtonInit -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.15.1998----------- + */ +void +plaxtonInit(int bitsPerLevel_) +{ + int ii; + int nParentBuckets; + struct sockaddr_in *me = &Config.Sockaddr.http->s; + HintCacheNodeKey *key; + + assert(nChildLists < 0); /* We shouldn't be initialized yet */ + + assert(!initialized); + initialized = 1; + + myNodeKey = NodeKK_Key(me); + /* + * List i contains all children that match me in i bits. + * Legal values for i are [0, BITS_PER_KEY] + */ + nChildLists = BITS_PER_KEY + 1; + assert(childrenListA == NULL); + childrenListA = (dlink_list *) xcalloc(nChildLists, sizeof(dlink_list)); + assert(childrenListA); + childrenCountA = (int *) xcalloc(nChildLists, sizeof(int)); + childrenCountTot = 0; + + /* + * Parents + */ + bitsPerLevel = bitsPerLevel_; + nParentLevels = (BITS_PER_KEY) / bitsPerLevel; + if ((BITS_PER_KEY) % bitsPerLevel != 0) { + nParentLevels++; + } + Plaxton_bucketsPerLevel = 1; + for (ii = 0; ii < bitsPerLevel; ii++) { + Plaxton_bucketsPerLevel *= 2; + } + nParentBuckets = Plaxton_bucketsPerLevel * nParentLevels; + maxParentBucket = nParentBuckets - 1; + assert(parentListA == NULL); + parentListA = (dlink_list *) xcalloc(nParentBuckets, sizeof(dlink_list)); + assert(parentListA); + assert(highestMatchA == NULL); + highestMatchA = (dlink_list *) xcalloc(BITS_PER_KEY, sizeof(dlink_list)); + assert(highestMatchA); + for (ii = 0; ii < BITS_PER_KEY; ii++) { + key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + hintCacheNodeKeyInit(key, &Config.Sockaddr.http->s); + dlinkAdd(key, &key->links, &highestMatchA[ii]); + } +} + +/* + *------------------------------------------------------------------ + * + * plaxtonDestroy -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998------ + */ +void +plaxtonDestroy(void) +{ + int ii; + + assert(initialized); + initialized = 0; + + assert(nChildLists > 0); /* Are we initialized? */ + for (ii = 0; ii < nChildLists; ii++) { + freeList(&childrenListA[ii]); + } + xfree(childrenListA); + childrenListA = NULL; + xfree(childrenCountA); + childrenCountA = NULL; + childrenCountTot = -999999; + nChildLists = -88888; + + /* + * Parents + */ + for (ii = 0; ii < nParentLevels * Plaxton_bucketsPerLevel; ii++) { + freeList(&parentListA[ii]); + } + xfree(parentListA); + parentListA = NULL; + nParentLevels = -8888; + bitsPerLevel = -8888; + Plaxton_bucketsPerLevel = -8888; + for (ii = 0; ii < BITS_PER_KEY; ii++) { + freeList(&highestMatchA[ii]); + } + xfree(highestMatchA); + highestMatchA = NULL; +} + + +/* + *------------------------------------------------------------------ + * + * freeList -- + * + * Free all elements on a list of HintCacheNodeKeys + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998-------- + */ +static void +freeList(dlink_list *list) +{ + dlink_node *node; + HintCacheNodeKey *k; + + assert(list); + for (node = list->head ; node; node = node->next) { + k = node->data; + dlinkDelete(node, list); + xfree(k); + } +} + +/* + *------------------------------------------------------------------ + * + * plaxtonAddChild -- + * + * Add the specified child to the list of children. + * We keep a separate list of children for each + * number of bits that can match the local addrss key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.9.1998--------- + */ +void +plaxtonAddChild(struct sockaddr_in *child) +{ + HintCacheNodeKey *key; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + key = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + hintCacheNodeKeyInit(key, child); + if (childFind(key)) { + xfree(key); + return; + } + childAdd(key); +} + +/* + *------------------------------------------------------------------ + * + * plaxtonRemoveChild -- + * + * Remove the specified child from its list of children. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------4.9.1998----- + */ +void +plaxtonRemoveChild(struct sockaddr_in *child) +{ + HintCacheNodeKey key, *found; + int match; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + hintCacheNodeKeyInit(&key, child); + found = childFind(&key); + if (found) { + dlinkDelete(&found->links, + List_Remove((dlink_node *) found); + xfree(found); + match = plaxtonMatchBits(key.key, myNodeKey); + childrenCountA[match]--; + childrenCountTot--; + assert(childrenCountA[match] >= 0); + assert(childrenCountTot >= 0); + return; + } + return; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonCheckIfChild -- + * + * Return nonzero if the specified node is listed + * as a child. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.9.1998------ + */ +int +plaxtonCheckIfChild(struct sockaddr_in *child) +{ + HintCacheNodeKey key, *found; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + hintCacheNodeKeyInit(&key, child); + found = childFind(&key); + if (found != NULL) { + return 1; + } + return 0; +} + + + + + +/* + *------------------------------------------------------------------ + * + * plaxtonChildQIndex -- + * + * Return the queue for which messages about the specified + * object should be stored. + * + * The rule is simple -- when I send a message to children about + * an object, I send it to all children who match that object's + * key in fewer bits than I do. (Unless I am the root + * for that object, in which case I send info to all + * nodes that think of me as a parent.) + * + * So, store messages for an object that matches me in i bits + * in queue i. Later, we will send it to all children + * that match me in i or fewer bits. (Store messages + * for objects for which I am root in queue nChildLists-1). + * + * As an optimization, if I have no children that match + * me in i or fewer bits, set *amILeaf to nozero. In that + * case, the caller may choose not to enqueue any message. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------5.1.1998------ + */ +int +plaxtonChildQIndex(URLKey * key, int iAmRoot, int *amILeaf) +{ + int match; + int leafCheck; + + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + + + if (iAmRoot) { + if ( /*childrenCountTot > 0 */ 1) { /* XXX */ + *amILeaf = 0; + return nChildLists - 1; + } else { + *amILeaf = 1; + return -999; + } + } + + match = plaxtonMatchBits(key->key, myNodeKey); + /* + * Check to see if I am a leaf for this object by looking + * at all childlists for children that match me in fewer bits + * than this object. If all such lists are empty, than I am + * a leaf. This is less inefficient than it seems. The expected + * number of queues I have to check is less than (1 + .5 + .25 + ...) + * (since I match in 0 bits half the time, ... ) + */ + *amILeaf = 1; + for (leafCheck = match - 1; leafCheck >= 0; leafCheck--) { + if (!List_IsEmpty(&childrenListA[leafCheck])) { + *amILeaf = 0; + break; + } + } + return match; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonNChildrenQs -- + * + * Return the number of queues of messages for children + * caller should allocate. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.10.1998--- + */ +int +plaxtonNChildrenQs(void) +{ + assert(initialized); + assert(nChildLists > 0); /* Are we initialized? */ + return nChildLists; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonGetChildAddrs -- + * + * Return the number of children for the specified message + * queue, allocate a buffer for that many addresses, + * and fill in that buffer with the children's addresses. + * + * Notice -- the question being asked is "to whom should + * I send messages for objects that match me in k bits?" + * The answer is all nodes that match in k *or fewer* bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * Allocates a vector for the addresses. Caller must free + * this vector when done. + * + * Note: the vector may be out of date by the time ther caller + * uses it. This is inherent problem -- even if caller sent + * all messages instantaneously, by the time they arrive + * at destination, the child could have left the system + * or a new child could have joined. + * + *----------------------------------------------------4.10.1998------- + */ +int +plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP) +{ + dlink_node *node; + int count; + int imatch; + HintCacheNodeKey *current; + int check; + + assert(initialized); + for (imatch = 0, count = 0; imatch <= qIndex; imatch++) { + count += childrenCountA[imatch]; + } + if (!count) { + *retAddrAP = NULL; + return 0; + } + *retAddrAP = + (struct sockaddr_in *) xmalloc(count * sizeof(struct sockaddr_in)); + for (imatch = 0, count = 0; imatch <= qIndex; imatch++) { + check = 0; + for (node = childrenListA[imatch].head; node; node = node->next) { + current = node->data; + check++; + (*retAddrAP)[count] = hintCacheNodeKeyGetAddr(current); + count++; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetChildAddrs: sending msg to child %s\n", + inet_ntoa((*retAddrAP)[count].sin_addr)); + } + assert(check == childrenCountA[imatch]); + } + return count; +} + + +/* + *------------------------------------------------------------------ + * + * nParentQs -- + * + * Return the number of parent q's to allocate. + * We need to account for both the normal case + * when we find a parent that matches an object + * in more bits than we do, and the root + * case when we match in k bits and so do some + * other nodes, but no one matches in more than + * k bits; in that case, we may not send + * to the closest node that matches us in k bits. + * + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.15.1998------- + */ +int +plaxtonNParentQs(void) +{ + int normalParentCount, rootCaseCount; + + assert(initialized); + assert(parentListA != NULL); + normalParentCount = nParentLevels * Plaxton_bucketsPerLevel; + rootCaseCount = BITS_PER_KEY; + return normalParentCount + rootCaseCount; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonParentQIndex -- + * + * Return the index of the parent queue to use + * for messages about the specified URLKey or + * set amIRoot to true if I have no parent + * for that object. + * + * I am trying to find someone who matches + * the object in more bits than I do. To + * reduce the number of levels of hierarchy + * I try to match bitsPerLevel bits at a + * time. + * + * If I match in at least l*bitsPerLevel bits but + * not in (l+1)*bitsPerLevel bits, then + * the parent is the node that matches in + * the most bits between (l+1)*bPL and (l)*bPL + * + * If there are multiple potential parents + * that match in the same number of bits, choose + * the closest one (all parent lists are maintained + * in sorted order) unless I also match the + * object in that many bits; in the latter case + * we need to decide on a root from among + * several equally qualified candidates. We + * always choose the node with the highest + * NodeKey in that case. + * + * Note the key invariant for avoiding loops: + * my parent always matches an object in more + * bits than I do or matches in as many bits + * as I do and has a higher ID. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998--------- + */ +int +plaxtonParentQIndex(URLKey * key, int *amIRoot) +{ + int match; + int nextLevelMatch; + int found, pindex; + + assert(initialized); + /* XXX */ + match = plaxtonMatchBits(key->key, myNodeKey); + if (match == nParentLevels * bitsPerLevel) { + /* + * Match all bits. I am root! + */ + *amIRoot = 1; + return -9999999; + } + + /* + * Try for full or partial match at next level. + */ + nextLevelMatch = ((match + bitsPerLevel) / bitsPerLevel) * bitsPerLevel; + found = scanForParentMatch(nextLevelMatch, match + 1, key, + &pindex, amIRoot); + if (found) { + assert(!*amIRoot); + return normalParentIndex(pindex); + } + + + /* + * I match in match bits, and didn't find anyone that matches + * in more. But, there may be other nodes that match the object + * in the same number of bits (but differ from me in some higher bit). + * We all need to agree on whom among us is the root. We need + * to do so in a way that avoids loops (and hopefully which + * gets everyone to agree on the same root.) Solution: if + * an object matches me in k bits and I know of no node + * that matches the object in more than k bits, choose as + * the root for that object, the node that matches the + * object (and me) in k bits and which has the highest + * known HintCacheNodeKey. + */ + assert(!List_IsEmpty(&highestMatchA[match])); + if (((HintCacheNodeKey *) List_First(&highestMatchA[match]))->key == myNodeKey) { + *amIRoot = 1; + return -999999; + } else { + *amIRoot = 0; + return highestMatchIndex(match); + } +} + + +/* + *------------------------------------------------------------------ + * + * scanForParentMatch -- + * + * Find the bucket index in parentsListA for + * a node matching between maxTry and minTry + * bits (inclusive) for the specified key. + * Return true if parent found and set + * parentIndexRet and amIRootRet. + * + * As we look at fewer and fewer bits we + * need to try all combinations of the + * high-order bits we are masking off. + * We currently do this by probing different + * entries in the table. It would be more + * efficient to maintain auxiliary data + * structures with all eligible nodes, + * but the data structures here are already + * more complicated than I like; Make it + * work first, then optimize performance later. + * + * Return the node that matches in the most + * possible bits. If more than one node + * matches in a specific # of bits, return the + * closest. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static int +scanForParentMatch(int maxTry, int minTry, const URLKey * key, + int *parentIndexRet, int *amIRootRet) +{ + HintCacheNodeKey *nk; + HintCacheKey tryKey; + int matchBits, permuteBits, permuteMax, ipermute; + int tryIndex; + int found = 0, bestIndex = -999999; + struct sockaddr_in bestSin, trySin; + + /* + * This code assumes that we are looking to match + * a "level" in the tree. + */ + assert(maxTry % bitsPerLevel == 0); + assert(maxTry - minTry < bitsPerLevel); + + for (matchBits = maxTry; matchBits >= minTry; matchBits--) { + /* + * Split the address into two parts, a set of low-order bits + * that must match the target and a set of high-order + * bits that are "don't care" for which we'll try all + * permutations. + */ + permuteBits = maxTry - matchBits; + permuteMax = (1 << permuteBits) - 1; + for (ipermute = 0; ipermute <= permuteMax; ipermute++) { + tryKey = makeMatchKey(key, matchBits, ipermute); + tryIndex = fullMatchIndex(tryKey); + if (parentListA[tryIndex].head != 0) { + /* parentListA[tryIndex] is not empty */ + nk = parentListA[tryIndex].head->data; + if (!found) { + found = 1; + *amIRootRet = 0; + bestSin = hintCacheNodeKeyGetAddr(nk); + bestIndex = tryIndex; + } else { + trySin = hintCacheNodeKeyGetAddr(nk); + if (HCHier_compareDistanceFromMe(bestSin.sin_addr, + trySin.sin_addr) > 0) { + bestSin = trySin; + bestIndex = tryIndex; + assert(*amIRootRet == 0); + } + } + } + } + if (found) { + assert(*amIRootRet == 0); + *parentIndexRet = bestIndex; + return 1; + } + } /* for matchBits */ + assert(!found); + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * makeMatchKey -- + * + * Return a key that matches the specified key in the + * bottom bits, and add the prefix + * permuteVal to the front. Remaining bits are all 0. + * For example, if key is 110101101, matchBits is 4, + * and permuteVal is 3 (11), then return + * 000111101 (zero-fill: 000 prefix: 11 match: 1101). + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static HintCacheKey +makeMatchKey(const URLKey * key, int matchBits, int permuteVal) +{ + HintCacheKey tryKey, matchMask; + + matchMask = (((HintCacheKey) 1) << matchBits) - 1; + tryKey = (key->key & matchMask) | (permuteVal << matchBits); + return tryKey; +} + + +/* + *------------------------------------------------------------------ + * + * highestMatchIndex -- + * + * Return the network buffer index that we should + * use for messages to the root node for objects + * that match us and some other node in + * bits and match no node in more than + * bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------4.15.1998----- + */ +static int +highestMatchIndex(int match) +{ + return maxParentBucket + 1 + match; +} + +/* + *------------------------------------------------------------------ + * + * normalParentIndex -- + * + * Return the network buffer index that we should + * use for parents that match in the specified bucket + * (where bucket is calculated as matchLevel * 2^bitsPerLevel + * + key%2^bitsPerLevel). + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.15.1998---- + */ +static int +normalParentIndex(int bucket) +{ + assert(bucket <= maxParentBucket); + return bucket; +} + +/* + *------------------------------------------------------------------ + * + * firstLevelBucketForMatch -- + * + * Return the index of the first bucket for the set + * of buckets for the first non-matching level for + * a key that we match in matchBits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998------- + */ +static int +firstLevelBucketForMatch(int match) +{ + int level; + + assert(match <= BITS_PER_KEY); + level = (match / bitsPerLevel) * Plaxton_bucketsPerLevel; + return level; +} + + + +/* + *------------------------------------------------------------------ + * + * plaxtonGetParentAddr -- + * + * Return the address to whom to send messages + * from the specified parent queue in *retAddr. + * Return nonzero on error. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998-------- + */ +int +plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr) +{ + assert(initialized); + assert(index >= 0); + assert(parentListA != NULL); + if (index <= maxParentBucket) { + if (!List_IsEmpty(&parentListA[index])) { + *retAddr = ((HintCacheNodeKey *) List_First(&parentListA[index]))->addr; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetParentAddr: Sending msg to parent %s\n", + inet_ntoa(retAddr->sin_addr)); + return 0; + } else { + return 1; + } + } else { + /* XXX index = index - maxParentBucket; */ + index = index - maxParentBucket - 1; + assert(index < BITS_PER_KEY); + assert(index >= 0); + /* + * List always contains at least me + */ + assert(!List_IsEmpty(&highestMatchA[index])); + if (((HintCacheNodeKey *) List_First(&highestMatchA[index]))->key == myNodeKey) { + return 1; + } else { + *retAddr = ((HintCacheNodeKey *) List_First(&highestMatchA[index]))->addr; + debug(HCPLAX_DEBUG, 2) + ("plaxtonGetParentAddr: Sending msg to parent %s\n", + inet_ntoa(retAddr->sin_addr)); + return 0; + } + } +} + +/* + *------------------------------------------------------------------ + * + * HCPLax_addNode -- + * + * Add a node to the lists of parents. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998-------- + */ +void +plaxtonAddNode(struct sockaddr_in *newNode) +{ + assert(initialized); + assert(newNode); +#if 1 /* XXX! - disabling parent&child lists */ + addNodeParentList(newNode); +#endif + addNodeHighestMatch(newNode); + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonRemoveNode -- + * + * Remove thenode from the lists of parents. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998------ + */ +void +plaxtonRemoveNode(struct sockaddr_in *goneNode) +{ + assert(initialized); + assert(goneNode); + removeNodeParentList(goneNode); + removeNodeHighestMatch(goneNode); + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonChangeDistance -- + * + * Change the distance (and perhaps the rank in sorted list) + * of the specified node. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.16.1998------- + */ +void +plaxtonchangeDistance(struct sockaddr_in *changeDistNode) +{ + assert(initialized); + assert(changeDistNode); + changeDistanceParentList(changeDistNode); + /* + * Don't need to tell HighestMatch list since that one is + * not sorted by distance. + */ + return; +} + +/* + *------------------------------------------------------------------ + * + * addNodeParentList -- + * + * See definition of parentListA where it is declared. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998----- + */ +static void +addNodeParentList(struct sockaddr_in *addNode) +{ + HintCacheNodeKey *n; + int index; + HintCacheNodeKey *current; + struct sockaddr_in s1, s2; + + n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + assert(n); + hintCacheNodeKeyInit(n, addNode); + + index = parentListIndex(n); + + + if (List_IsEmpty(&parentListA[index])) { + List_Insert((dlink_node *) n, LIST_ATFRONT(&parentListA[index])); + return; + } else { + LIST_FORALL2(&parentListA[index], HintCacheNodeKey *, current) { + if (HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current).sin_addr, + addNode->sin_addr) > 0) { + List_Insert((dlink_node *) n, LIST_BEFORE(current)); + return; + } + /* + * Check invariant that list is sorted by distance from me. + */ + if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) { + s1 = hintCacheNodeKeyGetAddr(current); + s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *) + current)); + assert(HCHier_compareDistanceFromMe(s1.sin_addr, + s2.sin_addr) <= 0); + } + } + } + List_Insert((dlink_node *) n, LIST_ATREAR(&parentListA[index])); + return; +} + +/* + *------------------------------------------------------------------ + * + * removeNodeParentList -- + * + * Remove the specified node from the parentList + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998--------- + */ +static void +removeNodeParentList(struct sockaddr_in *goneNode) +{ + int index; + dlink_node *node; + HintCacheNodeKey n, *current; + struct sockaddr_in s1, s2; + + hintCacheNodeKeyInit(&n, goneNode); + + index = parentListIndex(&n); + + for (node = parentListA[index]; node; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(&n, current)) { + dlinkDelete(node, &parentListA[index]); + xfree(current); + return; + } + /* + * Check invariant that list is sorted by distance from me. + */ + if ((dlink_node *) current != LIST_ATREAR(&parentListA[index])) { + s1 = hintCacheNodeKeyGetAddr(current); + s2 = hintCacheNodeKeyGetAddr((HintCacheNodeKey *) List_Next((dlink_node *) current)); + assert(hintCacheHierCompareDistanceFromMe(s1.sin_addr, s2.sin_addr) <= 0); + } + } +} + +/* + *------------------------------------------------------------------ + * + * changeDistanceParentList -- + * + * Since we need to keep this list sorted by distance + * from me, we need to reorder it if the distance + * to some node changes. + * + * Note: right now we do the simple thing -- remove + * and add the node. Faster implementations are possible. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998-------- + */ +static void +changeDistanceParentList(struct sockaddr_in *changeDistNode) +{ + removeNodeParentList(changeDistNode); + addNodeParentList(changeDistNode); +} + + +/* + *------------------------------------------------------------------ + * + * parentListIndex -- + * + * Return the index of the parent list for the element + * with the specified nodeKey. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998------ + */ +static int +parentListIndex(HintCacheNodeKey * n) +{ + return fullMatchIndex(n->key); +} + +/* + *------------------------------------------------------------------ + * + * fullMatchIndex -- + * + * Return the highest legal index into the parent list + * for object/node with the specified key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998------ + */ +static int +fullMatchIndex(HintCacheKey k) +{ + int bits, levelsThatMatch, indexInBucket, index; + + bits = plaxtonMatchBits(k, myNodeKey); + if (bits == nParentLevels * bitsPerLevel) { + /* + * I am root! want to match in all bits in last level + * This will force system to get right indexInBucket in + * last level. + */ + bits--; + } + levelsThatMatch = bits / bitsPerLevel; + indexInBucket = + (k >> (levelsThatMatch * bitsPerLevel)) % Plaxton_bucketsPerLevel; + index = firstLevelBucketForMatch(bits) + indexInBucket; + return index; +} + + +/* + *------------------------------------------------------------------ + * + * addNodeHighestMatch -- + * + * Add the specified node to all highestMatch lists k + * for for which the node matches me in at least the + * bottom k bits. Keep each list sorted by key with + * the head of the list containing the highest key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.16.1998------ + */ +static void +addNodeHighestMatch(struct sockaddr_in *addNode) +{ + HintCacheNodeKey n; + int match, imatch; + + hintCacheNodeKeyInit(&n, addNode); + + match = plaxtonMatchBits(n.key, myNodeKey); + if (match == BITS_PER_KEY) { + match--; + } + for (imatch = 0; imatch <= match; imatch++) { + matchInsert(&highestMatchA[imatch], addNode); + } + return; +} + +/* + *------------------------------------------------------------------ + * + * matchInsert -- + * + * Insert new node key onto list sorted by node key. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------4.16.1998---- + */ +static void +matchInsert(dlink_list *l, struct sockaddr_in *a) +{ + HintCacheNodeKey *current, *n; + dlink_node *node; + + n = (HintCacheNodeKey *) xmalloc(sizeof(HintCacheNodeKey)); + assert(n); + hintCacheNodeKeyInit(n, a); + + /* + * Each list always contains at least me. + */ + assert(l->head != 0); + + for (node = l->head; node; node = node->next) { + current = node->data; + assert(current->key != n->key); + if (current->key < n->key) { + /* Put 'n' right before 'current' */ + n->next = current; + n->prev = current->prev; + current->prev = current; + n->prev->next = n; + return; + } + } + assert(((HintCacheNodeKey *) l->tail->data)->key >= n->key); + dlinkAddTail(n, &n->links, l); + return; +} + +/* + *------------------------------------------------------------------ + * + * removeNodeHighestMatch -- + * + * Remove node from all lists k where node's key + * matches my key in at least k bits. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------4.16.1998---------- + */ +static void +removeNodeHighestMatch(struct sockaddr_in *goneNode) +{ + HintCacheNodeKey n; + int match, imatch; + + hintCacheNodeKeyInit(&n, goneNode); + + match = plaxtonMatchBits(n.key, myNodeKey); + if (match == BITS_PER_KEY) { + match--; + } + for (imatch = 0; imatch <= match; imatch++) { + matchRemove(&highestMatchA[imatch], goneNode); + } + return; +} + +/* + *------------------------------------------------------------------ + * + * matchRemove -- + * + * Remove specified element from list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------4.16.1998----------- + */ +static void +matchRemove(dlink_llist *list, struct sockaddr_in *a) +{ + HintCacheNodeKey *current, n; + dlink_node *node; + + hintCacheNodeKeyInit(&n, a); + /* + * Each list always contains at least me. + */ + assert(list->head != 0); + + for (node = list->head; node; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(current, &n)) { + dlinkDelete(node, list); + xfree(current); + return; + } + } + return; +} + +/* + *------------------------------------------------------------------ + * + * plaxtonCheckIfParent -- + * + * Return true if the specified node is, in fact, our + * current parent for objects with the specified URL. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +int +plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate) +{ + int index, amIRoot; + struct sockaddr_in real; + + assert(initialized); + index = plaxtonParentQIndex(&key, &amIRoot); + if (amIRoot) { + return 0; + } + if (plaxtonGetParentAddr(index, &real)) { + return 0; + } + if (candidate->sin_addr.s_addr == real.sin_addr.s_addr) { + return 1; + } + return 0; +} + + + + +/* + *------------------------------------------------------------------ + * + * childAdd -- + * + * Add a child record to the appropriate child list. + * Does NOT check to see if child is already on list -- + * caller should already have done it. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.9.1998---------- + */ +static void +childAdd(HintCacheNodeKey * key) +{ + int l; + + l = plaxtonMatchBits(key->key, myNodeKey); + assert(l <= nChildLists); + dlinkAdd(key, &key->links, childrenListA[l]); + childrenCountA[l]++; + childrenCountTot++; + assert(childFind(key)); + return; +} + +/* + *------------------------------------------------------------------ + * + * childFind -- + * + * Find the specified child if on the list. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------4.9.1998--------- + */ +static HintCacheNodeKey * +childFind(HintCacheNodeKey * key) +{ + HintCacheNodeKey *current; + dlink_node *node; + int l; + + l = plaxtonMatchBits(key->key, myNodeKey); + assert(l <= nChildLists); + for (node = childrenListA[l].head; node ; node = node->next) { + current = node->data; + if (!hintCacheNodeKeyCompare(current, key)) { + return current; + } + } + return NULL; +} + + +/* + *------------------------------------------------------------------ + * + * matchBits -- + * + * Return the number of bits that match between the two + * keys. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +int +plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2) +{ + int ibit; + HintCacheKey mask; + + for (ibit = 0, mask = 0x1; ibit < nChildLists - 1; ibit++, mask = mask << 1) { + if ((k1 & mask) != (k2 & mask)) { + return ibit; + } + } + return ibit; +} + + +/* + *------------------------------------------------------------------ + * + * plaxtonmyNodeKey -- + * + * description. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +HintCacheKey +plaxtonmyNodeKey(void) +{ + return myNodeKey; +} + + +#ifdef DOTEST +/* + *------------------------------------------------------------------ + * + * plaxtonSelfTest -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.10.1998------ + */ + +void +plaxtonSelfTest() +{ + printf("plaxtonSelfTest..."); + fflush(stdout); + testMakeMatchKey(); + neighborsOutgoing = (HCNet *) xmalloc(sizeof(HCNet)); + assert(neighborsOutgoing); + printf("."); + fflush(stdout); + HCNet_Init(neighborsOutgoing); + HCNet_SetTestMode(neighborsOutgoing); + selfTestChildren(); + printf("."); + fflush(stdout); + selfTestParents(); + printf("."); + fflush(stdout); + HCNet_Destroy(neighborsOutgoing); + xfree(neighborsOutgoing); + printf(".Done.\n"); + fflush(stdout); + return; +} + +/* + *------------------------------------------------------------------ + * + * selfTestChildren -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +selfTestChildren() +{ + int iaddr; + struct sockaddr_in n0; + static int CHECK_ADDR_BEGIN = 1000; + static int CHECK_ADDR_END = 2000; + static int CHECK_NOT_THERE_END = 3000; + static URLKey urlMatchAll, urlMatchNone, urlMatchOne, urlMatchEight; + int amILeaf = -1; + int childCount, allChildren; + struct sockaddr_in *childrenA = NULL; + + assert(CHECK_ADDR_END > CHECK_ADDR_BEGIN); + assert(CHECK_ADDR_END < CHECK_NOT_THERE_END); + + + + allChildren = CHECK_ADDR_END - CHECK_ADDR_BEGIN; + plaxtonInit(8); + + assert(sizeof(URLKey) == sizeof(HintCacheKey)); /* bypassing normal init */ + urlMatchAll.key = myNodeKey; + urlMatchNone.key = ~myNodeKey; + urlMatchOne.key = (~myNodeKey) ^ 0x1; + urlMatchEight.key = (~myNodeKey) ^ 0xFF; + + assert(plaxtonNChildrenQs() == sizeof(HintCacheKey) * 8 + 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchAll, 0, + &amILeaf) == sizeof(HintCacheKey) * 8); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchNone, 0, &amILeaf) == 0); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchOne, 0, &amILeaf) == 1); + assert(amILeaf == 1); + amILeaf = -1; + assert(plaxtonChildQIndex(&urlMatchEight, 0, &amILeaf) == 8); + assert(amILeaf == 1); + childrenA = (struct sockaddr_in *) 0x888888; + childCount = plaxtonGetChildAddrs(15, &childrenA); + assert(childCount == 0); + assert(childrenA == NULL); + + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + plaxtonAddChild(&n0); + } + + childCount = plaxtonGetChildAddrs(sizeof(HintCacheKey) * 8, &childrenA); + assert(childCount == allChildren); + assert(childrenA != NULL); + assert(selfTestFindAddr(CHECK_ADDR_BEGIN, childrenA, childCount)); + assert(selfTestFindAddr((CHECK_ADDR_BEGIN + CHECK_ADDR_END) / 2, + childrenA, childCount)); + assert(selfTestFindAddr(CHECK_ADDR_END - 1, childrenA, childCount)); + assert(!selfTestFindAddr(CHECK_ADDR_END, childrenA, childCount)); + xfree(childrenA); + + /* + * The nodes we inserted as children were random. Assuming + * we inserted a reasonable number of them, it would be + * surprizing if more than, say, 60% matched us in the + * lowest bit or if fewer than, say, 40% match us in the + * lowest bit + */ + if (allChildren >= 1000) { + childCount = plaxtonGetChildAddrs(0, &childrenA); + if (allChildren * 0.6 < childCount) { + printf("WARNING WARNING WARNING WARNING\n"); + printf + ("WARNING: Plaxton saw unlikely distribution of random children.\n"); + printf + ("WARNING: (too many). This is very nearly an assertion failure.\n"); + } + if (allChildren * 0.4 > childCount) { + printf("WARNING WARNING WARNING WARNING\n"); + printf + ("WARNING: Plaxton saw unlikely distribution of random children.\n"); + printf + ("WARNING: (too few). This is very nearly an assertion failure.\n"); + } + xfree(childrenA); + } else { + printf + ("\nWARNING: Plaxton selftest skipping random match check (too few samples\n"); + } + + printf("."); + fflush(stdout); + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_ADDR_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + assert(plaxtonCheckIfChild(&n0)); + plaxtonRemoveChild(&n0); + } + printf("."); + fflush(stdout); + for (iaddr = CHECK_ADDR_BEGIN; iaddr < CHECK_NOT_THERE_END; iaddr++) { + n0.sin_addr.s_addr = iaddr; + n0.sin_port = 0; + assert(!plaxtonCheckIfChild(&n0)); + } + plaxtonDestroy(); + printf(".OK\n"); +} + + + +/* + *------------------------------------------------------------------ + * + * selfTestFindAddr -- + * + * Return nonzero if the specified value is in + * the array. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.10.1998------- + */ +static int +selfTestFindAddr(int addr, struct sockaddr_in *childrenA, int childCount) +{ + struct sockaddr_in n0; + int ii; + + assert(childrenA != NULL); + n0.sin_addr.s_addr = addr; + n0.sin_port = 0; + for (ii = 0; ii < childCount; ii++) { + assert(childrenA[ii].sin_port == 0); + if (childrenA[ii].sin_addr.s_addr == n0.sin_addr.s_addr) { + return 1; + } + } + return 0; +} + + +/* + *------------------------------------------------------------------ + * + * selfTestParents -- + * + * description. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998-------- + */ +static void +selfTestParents(void) +{ + testParentsBinaryTree(); + testParentsMultiRootCase(); + testParentsInternals(); + testParentsInternals2(); + stressTestParents(); +} + +/* + *------------------------------------------------------------------ + * + * testParentsBinaryTree -- + * + * Test the following simple case: four nodes + * with low-order bits: 00 01 10 11 + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998-------- + */ +static void +testParentsBinaryTree(void) +{ + int myId, targetId, caseCount; + struct sockaddr_in parents[4], retAddr; + int ii, hops, qIndex, iAmRoot; + HintCacheNodeKey key; + URLKey targetURLKey; + + /* XXX Make sure that entire code merge happens. Funny little bug in + * tools.h that we fixed. + */ + parents[0].sin_addr.s_addr = 10; + parents[0].sin_port = 0; + parents[1].sin_addr.s_addr = 11; + parents[1].sin_port = 0; + assert(SINCMP(&parents[0], &parents[1])); /* if this fails, bug in SINCMP */ + + /* + * Try this test from every point of view + */ + for (myId = 0; myId < 4; myId++) { + plaxtonInit(1); + assert(plaxtonNParentQs() == 192); + + + /* + * Cheat to force my key to do right thing + */ + myNodeKey = (HintCacheKey) myId; + for (ii = 0; ii < BITS_PER_KEY; ii++) { + assert(highestMatchA[ii].head != 0); + ((HintCacheNodeKey *) highestMatchA[ii].head->data)->key = myNodeKey; + } + + for (caseCount = 1; caseCount <= 3; caseCount++) { + /* + * Do all combinations of bottom two bits except my own + */ + targetId = myId ^ caseCount; + /* + * Search for a node that matches desired bits + */ + for (ii = 0;; ii++) { + parents[caseCount].sin_addr.s_addr = myId * 1000 + ii; + parents[caseCount].sin_port = 0; + hintCacheNodeKeyInit(&key, &parents[caseCount]); + if ((key.key & 0x3) == targetId) { + if (caseCount == 1) { + assert((key.key & 0x2) == (myNodeKey & 0x2)); + assert((key.key & 0x1) != (myNodeKey & 0x1)); + hops = 1; + } else { + assert((key.key & 0x2) != (myNodeKey & 0x2)); + hops = 2; + } + HCHier_newNode(&parents[caseCount], hops, 999); + + break; + } + } + } + + + /* + * Case 0: same in all bits + */ + targetURLKey.key = myId; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(iAmRoot); + + + /* + * Case 1: differ in bit 0 --> queue is at level 0 + * and the (key & 0x1)th queue within level 0 + */ + targetURLKey.key = myId ^ 0x1; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == ((unsigned) targetURLKey.key & 0x1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr); + assert(plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + + /* + * Case 2: differ in bit 1; same bit 0 --> queue is + * at level 1 and the (key & 0x1)the queue within level 1 + */ + targetURLKey.key = myId ^ 0x2; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == 2 + (((unsigned) targetURLKey.key & 0x2) >> 1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[2].sin_addr.s_addr); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + /* + * Case 3: differ in bits 0 and 1; should be same as case 1 + */ + targetURLKey.key = myId ^ 0x3; + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(!iAmRoot); + assert(qIndex == ((unsigned) targetURLKey.key & 0x1)); + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(retAddr.sin_addr.s_addr == parents[1].sin_addr.s_addr); + assert(plaxtonCheckIfParent(targetURLKey, &parents[1])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[2])); + assert(!plaxtonCheckIfParent(targetURLKey, &parents[3])); + + plaxtonDestroy(); + } +} + +/* + *------------------------------------------------------------------ + * + * testParentsMultiRootCase -- + * + * Test the case where several nodes match + * an object in k bits, and no nodes match in + * more than k bits. Answer should be that the + * highest key is the winner. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------4.19.1998-------- + */ +static void +testParentsMultiRootCase(void) +{ + int eligibleFound, ii; + struct sockaddr_in sin, maxAddr, retAddr; + static unsigned int nodeMask = 0xFF; + static unsigned int objMask = 0x3F; + HintCacheKey maxKey; + URLKey targetURLKey; + int qIndex, iAmRoot; + HintCacheNodeKey anotherNodeKey; + + plaxtonInit(2); + + assert(objMask < nodeMask); + assert((objMask & nodeMask) == objMask); + + /* + * Create a bunch of nodes that are eligible to be the root for + * for an object that matches them (and us) in objMask bits + * and mismatches in the next bit + */ + /* XXX targetURLKey.key = (myNodeKey & objMask) ^ (nodeMask ^ objMask); */ + targetURLKey.key = (myNodeKey & nodeMask) ^ (nodeMask ^ objMask); + + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + assert(iAmRoot); + + maxKey = myNodeKey; + maxAddr = Config.Sockaddr.http->s; + ii = 0; + eligibleFound = 0; + while (eligibleFound < 40) { + sin.sin_addr.s_addr = 10000 + ii; + sin.sin_port = 0; + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + if ((anotherNodeKey.key & nodeMask) == (myNodeKey & nodeMask)) { + eligibleFound++; + HCHier_newNode(&sin, 1000, 999); + if (anotherNodeKey.key > maxKey) { + /* + * Found new root for object + */ + maxKey = anotherNodeKey.key; + maxAddr = sin; + } + } + qIndex = plaxtonParentQIndex(&targetURLKey, &iAmRoot); + if (maxKey == myNodeKey) { + assert(iAmRoot); + } + if (iAmRoot) { + assert(maxKey == myNodeKey); + } else { + assert(plaxtonGetParentAddr(qIndex, &retAddr) == 0); + assert(qIndex >= nParentLevels * plaxtonbucketsPerLevel); + assert(retAddr.sin_addr.s_addr == maxAddr.sin_addr.s_addr); + } + ii++; + } + plaxtonDestroy(); + +} + + +/* + *------------------------------------------------------------------ + * + * stressTestParents -- + * + * Add and remove a few bizillion nodes and elements. I don't + * know what the right answers should be, but + * I want to test to try to trigger assertion failures. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-----------------------------------------------------4.19.1998-------- + */ +static void +stressTestParents(void) +{ + int ii; + URLKey targetURLKey; + int qIndex, iamRoot; + static int BIG = 100; /* should be much bigger for good test */ + struct sockaddr_in sin, retAddr; + + plaxtonInit(4); + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + HCHier_newNode(&sin, 1000, 999); + } + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + plaxtonchangeDistance(&sin); + } + + + for (ii = 0; ii < BIG; ii++) { + targetURLKey.key = ii; + qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot); + if (!iamRoot) { + assert(!plaxtonGetParentAddr(qIndex, &retAddr)); + } + } + + for (ii = 0; ii < BIG; ii++) { + sin.sin_addr.s_addr = 100000 + ii; + sin.sin_port = 0; + HCHier_delNode(&sin, 1000, 1999); + } + + for (ii = 0; ii < BIG; ii++) { + targetURLKey.key = ii; + qIndex = plaxtonParentQIndex(&targetURLKey, &iamRoot); + if (!iamRoot) { + assert(!plaxtonGetParentAddr(qIndex, &retAddr)); + } + } + + plaxtonDestroy(); +} + + +/* + *------------------------------------------------------------------ + * + * testParentsInternals -- + * + * Test the internal data structures of the parents + * for the non-multi-root case. + * Set the local key address to 0 then + * generate a quand-ary tree with all possible + * values of node keys from 1..15, and make + * sure that the nodes land in the right buckets + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------ + */ +static void +testParentsInternals(void) +{ + int ii, targetKey; + HintCacheNodeKey anotherNodeKey, *current, *next; + HintCacheKey k; + struct sockaddr_in sin, nodes[16]; + int iAmRoot; + URLKey urlKey; + dlink_node *node; + + plaxtonInit(2); + myNodeKey = 0; /* Fake it out to make tests easier to write and read */ + + targetKey = 1; + ii = 0; + while (targetKey < 16) { + /* + * Note: netdb only keeps distance info on granularity of + * networks; we want to know what distances there are between + * nodes, so make nodes be on different (hopfully unused) subnets + */ + sin.sin_addr.s_addr = 15000 + ii * 255; + sin.sin_port = 0; + if (netdbHintHops(sin.sin_addr)) + !=0) { + ii++; + continue; /* Someone already used this address and gave it a distance */ + } + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + if ((anotherNodeKey.key & 15) == targetKey) { + nodes[targetKey] = sin; + HCHier_newNode(&sin, targetKey * 1000, 999); + targetKey++; + } + ii++; + } + + /* + * The level-0 lists should be in sorted order + */ + for (ii = 1; ii <= 3; ii++) { + for (node = parentListA[ii].head; node; node = node->next) { + current = node->data; + if (current != (HintCacheNodeKey *) parentListA[ii].tail->data)) { + next = (HintCacheNodeKey *) List_Next((dlink_node *) current); + assert(!List_IsAtEnd(&parentListA[ii], (dlink_node *) next)); + assert(HCHier_compareDistanceFromMe(hintCacheNodeKeyGetAddr(current). + sin_addr, hintCacheNodeKeyGetAddr(next).sin_addr) + <= 0); + } + } + } + + /* + * The level-0 lists XX01, XX10, and XX11 should each have + * four elements in the following order: 00--, 01--, 10--, + * and 11-- (where "--" is the index of the list) + */ + for (ii = 1; ii <= 3; ii++) { + assert((&parentListA[ii])->prevPtr + == (&parentListA[ii])->nextPtr->nextPtr->nextPtr->nextPtr); + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 0); /* 00 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 1); /* 01 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 2); /* 10 */ + + k = ((HintCacheNodeKey *) ((&parentListA[ii])->nextPtr->nextPtr->nextPtr-> + nextPtr))->key; + assert((k & 3) == ii); + assert(((k & 15) >> 2) == 3); /* 11 */ + + urlKey.key = 0xFFAA3400 | ii; + assert(plaxtonCheckIfParent(urlKey, &nodes[ii])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == ii); + assert(!iAmRoot); + } + /* + * The level-1 lists 0100, 1000, 1100 should each + * have one element + */ + /* 00 00 is list 4 and is empty */ + assert(List_IsEmpty(&parentListA[4])); + + /* 01 00 is list 5 and has one element "xxx0100" = 4 */ + assert(parentListA[5].nextPtr->nextPtr == &parentListA[5]); + k = ((HintCacheNodeKey *) ((&parentListA[5])->nextPtr))->key; + assert((k & 15) == 4); + urlKey.key = 0xFFAA1204; + assert(plaxtonCheckIfParent(urlKey, &nodes[4])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 5); + assert(!iAmRoot); + + /* 10 00 is list 6 and has one element "xxx1000" = 8 */ + assert(parentListA[6].nextPtr->nextPtr == &parentListA[6]); + k = ((HintCacheNodeKey *) ((&parentListA[6])->nextPtr))->key; + assert((k & 15) == 8); + urlKey.key = 0xFFAA1208; + assert(plaxtonCheckIfParent(urlKey, &nodes[8])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 6); + assert(!iAmRoot); + + /* 11 00 is list 7 and has one element "xxx1100" = 12 */ + assert(parentListA[7].nextPtr->nextPtr == &parentListA[7]); + k = ((HintCacheNodeKey *) ((&parentListA[7])->nextPtr))->key; + assert((k & 15) == 12); + urlKey.key = 0xFFAA120C; + assert(plaxtonCheckIfParent(urlKey, &nodes[12])); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 7); + assert(!iAmRoot); + + plaxtonDestroy(); +} + + +/* + *------------------------------------------------------------------ + * + * testParentsInternals2 -- + * + * Test finding parent when we can't match + * entire next level. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------5.4.1998---- + */ +static void testParentsInternals2(void) +{ + int ii; + struct sockaddr_in sin; + HintCacheNodeKey anotherNodeKey; + URLKey urlKey; + int iAmRoot; + + plaxtonInit(4); + myNodeKey = 0; /* Fake it out to make tests easier to write and read */ + + ii = 0; + while (1) + { + /* + * Note: netdb only keeps distance info on granularity of + * networks; so make nodes be on different (hopfully unused) subnets + */ + sin.sin_addr.s_addr = 15000 + ii * 255; + sin.sin_port = 0; + if (netdbHintHops(sin.sin_addr) != 0) + { + ii++; + continue; /* Someone already used this address and gave it a distance */ + } + hintCacheNodeKeyInit(&anotherNodeKey, &sin); + /* + * Want 0110 0000 + */ + if ((anotherNodeKey.key & 0xFF) == 0x60) { + HCHier_newNode(&sin, 1000, 999); + break; + } + ii++; + } + assert((anotherNodeKey.key & 0xFF) == 0x60); + urlKey.key = 0x20; + assert(plaxtonCheckIfParent(urlKey, &sin)); + assert(plaxtonParentQIndex(&urlKey, &iAmRoot) == 22); + assert(!iAmRoot); + plaxtonDestroy(); +} + +/* + *------------------------------------------------------------------ + * + * testMakeMatchKey -- + * + * description. + * + * Arguments: + * None. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------5.4.1998------ + */ +static void testMakeMatchKey(void) +{ + URLKey key; + HintCacheKey ret; + + key.key = 0xFFAABBCC; + ret = makeMatchKey(&key, 4, 0); + assert(ret == 0xC); + ret = makeMatchKey(&key, 4, 0xD); + assert(ret = 0xDC); + ret = makeMatchKey(&key, 0, 0xD); + assert(ret = 0xD); +} + +#endif /* DOTEST */ Index: squid/src/access_log.c diff -u squid/src/access_log.c:1.17 squid/src/access_log.c:1.15.2.2 --- squid/src/access_log.c:1.17 Sun Jun 16 10:48:14 2002 +++ squid/src/access_log.c Tue Sep 3 10:41:34 2002 @@ -64,6 +64,7 @@ "TCP_MEM_HIT", "TCP_DENIED", "TCP_OFFLINE_HIT", + "TCP_PUT", #if LOG_TCP_REDIRECTS "TCP_REDIRECT", #endif @@ -72,6 +73,7 @@ "UDP_DENIED", "UDP_INVALID", "UDP_MISS_NOFETCH", + "UDP_PUT", "ICP_QUERY", "LOG_TYPE_MAX" }; Index: squid/src/acl.c diff -u squid/src/acl.c:1.55 squid/src/acl.c:1.42.2.3 --- squid/src/acl.c:1.55 Sun Sep 1 09:30:41 2002 +++ squid/src/acl.c Tue Sep 3 10:41:35 2002 @@ -363,7 +363,7 @@ protocol_t protocol; for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); while ((t = strtokFile())) { - protocol = urlParseProtocol(t); + protocol = urlParseProtocol(t, 0, 0); q = memAllocate(MEM_INTLIST); q->i = (int) protocol; *(Tail) = q; Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.47 squid/src/cache_cf.c:1.38.2.4 --- squid/src/cache_cf.c:1.47 Sun Sep 1 09:30:41 2002 +++ squid/src/cache_cf.c Tue Sep 3 10:41:37 2002 @@ -1535,6 +1535,21 @@ p->options.allow_miss = 1; } else if (!strncasecmp(token, "max-conn=", 9)) { p->max_conn = xatoi(token + 9); + } else if (!strncasecmp(token, "dist", 4)) { + p->options.dist = 1; + } else if (!strncasecmp(token, "fwdpush", 7)) { + p->fwdpush = DistAllPeers; + DistAllPeers = p; +#if USE_ICP_DATA + } else if (!strncasecmp(token, "icpdata", 7)) { + p->options.icpdata = 1; + } else if (!strncasecmp(token, "maxrate=", 8)) { + p->maxrate = atoi(token + 8); +#endif +#if USE_HINT_CACHE + } else if (!strncasecmp(token, "nohint", 6)) { + p->options.nohint = 1; +#endif } else { debug(3, 0) ("parse_peer: token='%s'\n", token); self_destruct(); Index: squid/src/cbdata.c diff -u squid/src/cbdata.c:1.15 squid/src/cbdata.c:1.14.2.2 --- squid/src/cbdata.c:1.15 Sat Apr 13 16:09:15 2002 +++ squid/src/cbdata.c Tue Sep 3 10:41:39 2002 @@ -136,6 +136,7 @@ CREATE_CBDATA_FREE(peer, peerDestroy); CREATE_CBDATA(ps_state); CREATE_CBDATA(RemovalPolicy); + CREATE_CBDATA(Pusher); CREATE_CBDATA(RemovalPolicyWalker); CREATE_CBDATA(RemovalPurgeWalker); CREATE_CBDATA(store_client); Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.79 squid/src/cf.data.pre:1.43.2.4 --- squid/src/cf.data.pre:1.79 Sun Sep 1 09:30:41 2002 +++ squid/src/cf.data.pre Tue Sep 3 10:41:39 2002 @@ -279,6 +279,8 @@ digest-url=url allow-miss max-conn + dist + nohint use 'proxy-only' to specify that objects fetched from this cache should not be saved locally. @@ -385,6 +387,19 @@ use 'max-conn' to limit the amount of connections Squid may open to this peer. + 'dist' tells squid to ask for consistency updates + via httpdist on all queries to that peer. + + 'nohint' tells squid not to send hint cache updates + to that peer. The default is that updates are sent + if hints are active. + + 'icpdata' says to send pushes to this peer by the + UDP-based ICPDATA protocol instead of TCP. + + 'maxrate=n' specifies the maximum rate to send + ICPDATA data at. + NOTE: non-ICP neighbors must be specified as 'parent'. DOC_END @@ -1405,6 +1420,11 @@ (off - for use when useragents generate nonce counts that occasionally miss 1 (ie, 1,2,4,6)). + "nonce_strictness" on|off + Determines if squid requires increment-by-1 behaviour for nonce counts + (on - the default), or strictly incrementing (off - for use when useragents + generate nonce counts that occasionally miss 1 (ie, 1,2,4,6)). + === NTLM scheme options follow === "program" cmdline @@ -3774,6 +3794,111 @@ time. By default it is set to 10% of the Cache Digest. DOC_END +NAME: hint_cache_listen +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_listen +DEFAULT: off +DOC_START + This controls whether hint cache is used to decide where to + forward misses. Hint caches exchange data to track nearest + location and metadata of all URLs in a hint cache cloud; + This variable also decides whether we listen to hints from + neighboring hint caches. +DOC_END + +NAME: hint_cache_advertise +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_advertise +DEFAULT: off +DOC_START + This controls whether we tell other caches about content in + our own cache. We only want to do that if we are in a + position to efficiently serve requests from other caches. + + We encourage you to turn this on, as participation in the + hint cloud as a full neighbor brings greater value to + everybody, including yourself. +DOC_END + +NAME: hint_cache_file +IFDEF: USE_HINT_CACHE +TYPE: string +LOC: Config.Hints.cache_file +DEFAULT: @DEFAULT_HINT_FILE@ +DOC_START + This is the name of the file holding the hint cache. +DOC_END + +NAME: hint_cache_size +COMMENT: bytes +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.size +DEFAULT: 83886080 +DOC_START + This is the size of the hint cache, in bytes. It has to be + big enough to hold location and metadata for all objects + tracked. +DOC_END + +NAME: hint_cache_assoc +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.assoc +DEFAULT: 4 +DOC_START + Hint cache associativity. +DOC_END + +NAME: hint_cache_interval +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.intvl +DEFAULT: 60 +DOC_START + Max interval between hint transmissions to neighbors, in + seconds. Actual interval is randomly, uniformly distributed + between 0 and hint_cache_interval. +DOC_END + +NAME: hint_cache_use_mmap +IFDEF: USE_HINT_CACHE +TYPE: onoff +LOC: Config.onoff.hint_cache_use_mmap +DEFAULT: off +DOC_START + This tells the hint cache to access the hint cache file + using mmap() instead of standard file I/O. A slight + speedup on machines with plenty of RAM. If you are not + so long on RAM for your cache, leave it off. It probably + isn't efficient unless you can hold almost the entire + cache in memory. See hint_cache_size, above, for how + big your hint cache is. +DOC_END + +NAME: hint_cache_join_interval +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.join_intvl +DEFAULT: 14400 +DOC_START + Max interval between join transmissions to neighbors, in + seconds. Actual interval is randomly, uniformly distributed + between 0 and hint_cache_join_interval. +DOC_END + +NAME: hint_cache_holddown +IFDEF: USE_HINT_CACHE +TYPE: int +LOC: Config.Hints.holddown +DEFAULT: 900 +DOC_START + Amount of time to pass before we can assume that a hint + has finished propagating. +DOC_END + NAME: chroot TYPE: string LOC: Config.chroot_dir Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.71 squid/src/client_side.c:1.45.2.5 --- squid/src/client_side.c:1.71 Sun Sep 1 09:30:42 2002 +++ squid/src/client_side.c Tue Sep 3 10:41:41 2002 @@ -1986,6 +1986,9 @@ } /* yes, continue */ http->log_type = LOG_TCP_MISS; + } else if (r->method == METHOD_PUT) { + putRecv(http); + return; } else { http->log_type = clientProcessRequest2(http); } @@ -2007,6 +2010,15 @@ http->entry->mem_obj->method = r->method; } http->sc = storeClientListAdd(http->entry, http); + if (r->dist_type != DIST_NONE) { + if (r->dist_type == DIST_DIST) + distNewUpdatee(http->entry, r->client_addr, r->dist_port); + else { + /* DIST_UNDIST */ + assert(r->dist_type == DIST_UNDIST); + distDelUpdatee(http->entry, r->client_addr, r->dist_port); + } + } #if DELAY_POOLS delaySetStoreClient(http->sc, delayClient(http)); #endif @@ -2252,7 +2264,8 @@ *(*prefix_p + prefix_sz) = '\0'; dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", (*prefix_p) + *req_line_sz_p); + debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", + http->hdr_str + *req_line_sz_p); #if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION if ((t = strchr(url, '#'))) /* remove HTML anchors */ *t = '\0'; @@ -2546,13 +2559,11 @@ if (nrequests == 0) fd_note(conn->fd, "Reading next request"); /* Process request */ - http = parseHttpRequest(conn, - &method, - &parser_return_code, - &prefix, - &req_line_sz); - if (!http) - safe_free(prefix); + http = parseHttpRequest(conn, + &method, + &parser_return_code, + &prefix, + &req_line_sz); if (http) { assert(http->req_sz > 0); conn->in.offset -= http->req_sz; @@ -2575,7 +2586,6 @@ err->request_hdrs = xstrdup(conn->in.buf); http->entry = clientCreateStoreEntry(http, method, null_request_flags); errorAppendEntry(http->entry, err); - safe_free(prefix); break; } if ((request = urlParse(method, http->uri)) == NULL) { @@ -2586,14 +2596,13 @@ http->al.http.code = err->http_status; http->entry = clientCreateStoreEntry(http, method, null_request_flags); errorAppendEntry(http->entry, err); - safe_free(prefix); break; } else { /* compile headers */ /* we should skip request line! */ - if (!httpRequestParseHeader(request, prefix + req_line_sz)) + if (!httpRequestParseHeader(request, http->hdr_str + req_line_sz)) debug(33, 1) ("Failed to parse request headers: %s\n%s\n", - http->uri, prefix); + http->uri, http->hdr_str); /* continue anyway? */ } request->flags.accelerated = http->flags.accel; @@ -2615,7 +2624,6 @@ request->content_length = httpHeaderGetInt(&request->header, HDR_CONTENT_LENGTH); request->flags.internal = http->flags.internal; - safe_free(prefix); safe_free(http->log_uri); http->log_uri = xstrdup(urlCanonicalClean(request)); request->client_addr = conn->peer.sin_addr; Index: squid/src/comm.c diff -u squid/src/comm.c:1.24 squid/src/comm.c:1.18.2.4 --- squid/src/comm.c:1.24 Thu Apr 18 23:30:40 2002 +++ squid/src/comm.c Tue Sep 3 10:41:42 2002 @@ -631,6 +631,9 @@ comm_close(int fd) { fde *F = NULL; +#if USE_ICP_DATA + int isvfd; +#endif debug(5, 5) ("comm_close: FD %d\n", fd); assert(fd >= 0); @@ -648,6 +651,9 @@ if (F->ssl) ssl_shutdown_method(fd); #endif +#if USE_ICP_DATA + isvfd = (conn->comm_type == SOCK_VIRTUAL); +#endif commSetTimeout(fd, -1, NULL, NULL); CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING); commCallCloseHandlers(fd); @@ -660,7 +666,18 @@ } #endif fd_close(fd); /* update fdstat */ +#if USE_ICP_DATA + if (isvfd) { + /* flag for later reuse */ + conn->comm_type = SOCK_VIRTUAL; + } + else { + debug(5, 9) ("comm_close: really closing fd %d \n", fd); + close(fd); + } +#else /* USE_ICP_DATA */ close(fd); +#endif /* USE_ICP_DATA */ statCounter.syscalls.sock.closes++; } @@ -1027,3 +1044,47 @@ return 0; return F->defer_check(fd, F->defer_data); } + +#if USE_ICP_DATA +/* + * Get fake file descriptor suitable for indexing through fd_table. + */ +int +comm_virtual_fd() +{ + static int firstfd = -1; + struct in_addr nobody; + int vfd; + int i; + + if (firstfd == -1){ + nobody.s_addr = INADDR_ANY; + firstfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual"); + vfd = firstfd; + } + else { + for (i = 0; i <= Biggest_FD; ++i) { + if (fd_table[i].comm_type == SOCK_VIRTUAL && !fd_table[i].openned) + break; + } + if (fd_table[i].comm_type != SOCK_VIRTUAL) { + nobody.s_addr = INADDR_ANY; + vfd = comm_open(SOCK_DGRAM, 0, nobody, 0, COMM_NONBLOCKING, "virtual"); + debug(5, 4, "comm_virtual_fd: opened new vfd %d (Biggest_FD = %d)\n", + vfd, Biggest_FD); + assert(vfd > -1); + } + else { + vfd = i; + } + } + + fdstat_open(vfd, FD_SOCKET); + memset((char *) &fd_table[vfd], '\0', sizeof(FD_ENTRY)); + fd_table[vfd].openned = 1; + fd_table[vfd].lifetime = -1; + fd_table[vfd].comm_type = SOCK_VIRTUAL; + debug(5, 7, "comm_virtual_fd: returning vfd %d \n", vfd); + return(vfd); +} +#endif /* USE_ICP_DATA */ Index: squid/src/defines.h diff -u squid/src/defines.h:1.24 squid/src/defines.h:1.15.2.4 --- squid/src/defines.h:1.24 Thu Aug 8 13:15:19 2002 +++ squid/src/defines.h Tue Sep 3 10:41:43 2002 @@ -313,6 +313,64 @@ #define O_BINARY 0 #endif +/* put.c */ +#define P_ACTIVE(p) ((p)->flags.connected | (p)->flags.connecting) + +#if USE_HINT_CACHE +/* Hint Cache Interface */ + +/* Not QUITE compatible with 1.0 due to different tolower treatment + of URLs before md5 coding. */ +#define HINT_CACHE_VERSION "2.0" /* Protocol version */ + +/* Returns true iff the hint cache is in operation. */ +#define HINT_CACHE_ACTIVE() (HCDisk != NULL) + +#define URLKEY_COMPARE(k1, k2) ((k1).key - (k2).key) + +/* Hint Cache Primitives */ +#define HCE_VALID(hce) ((hce)->ipaddr.s_addr != INADDR_ANY &&\ + URLKEY_COMPARE((hce)->key, INVALID_URL_KEY)) +#define HCE_INVALIDATE(hce) ((hce)->ipaddr.s_addr = INADDR_ANY, \ + (hce)->key = INVALID_URL_KEY); + +#define HINT_CACHE_KEY(e) (((URLKey *) ((e)->hchash.key))) + +/* Hint protocol event types */ +#define HC_InvalToParent 1 +#define HC_InvalToChild 2 +#define HC_InformToParent 3 +#define HC_InformToChild 4 +#define HC_NewVersion 5 +#define HC_Join 6 +#define HC_Leave 7 +#define HC_Ignore 8 /* Message supressed. Ignore it. */ +#define HC_NotChild 9 /* "I am not your child" */ +#define HC_Error 10 + +/* Smallest an HCUPDATE can be (e.g., length of a v1 update). */ +#define HCU_MINLEN 24 + +/* Hint Cache Disk */ +#define HCD_VERSION 2 + +#define HCD_PREFETCH_THRESH 3 + +#endif /* USE_HINT_CACHE */ + + +/* CygWin & Windows NT Port */ +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#define _WIN_OS_UNKNOWN 0 +#define _WIN_OS_WIN32S 1 +#define _WIN_OS_WIN95 2 +#define _WIN_OS_WIN98 3 +#define _WIN_OS_WINNT 4 +#define _WIN_OS_WIN2K 5 +#define _WIN_OS_WINXP 6 +#endif + +#define HTTP_REQBUF_SZ 4096 /* * Macro to find file access mode */ Index: squid/src/dist.c diff -u /dev/null squid/src/dist.c:1.1.2.5 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/dist.c Mon May 20 19:46:42 2002 @@ -0,0 +1,217 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * Distribution network algorithm. + * + * AUTHOR: Jon Kay, 1997 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +static void distUpdate(Updatee *u); + +static char urlbuf[MAX_URL + 48]; + +peer *DistAllPeers = 0; + +/* Create new updatee ds & add to object's updatee list */ +Updatee * +distNewUpdatee(StoreEntry *entry, struct in_addr host, u_short dport) +{ + Updatee *u; + + ++statCounter.dist.dists; + /* Don't add a client if it isn't interested in updates */ + if (dport == 0) + return(NULL); + + /* Make sure new guy isn't already on list */ + for (u = entry->updatees; u; u = u->next) { + if (u->saddr.sin_addr.s_addr == host.s_addr + && u->saddr.sin_port == dport) + return(u); + } + + /* Need new updatee, alloc and add to list */ + u = xcalloc(sizeof(*u), 1); + u->next = entry->updatees; + u->entry = entry; + u->saddr.sin_family = AF_INET; + u->saddr.sin_addr = host; + u->saddr.sin_port = dport; + u->lastmod = entry->lastmod; + entry->updatees = u; + ++statCounter.dist.updatees; + return(u); +} + +void +distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport) +{ + Updatee *i, **optr; + + ++statCounter.dist.undists; + optr = &entry->updatees; + for (i = entry->updatees; i; i = i->next) { + if (i->saddr.sin_addr.s_addr == host.s_addr + && i->saddr.sin_port == dport) { + (*optr) = i->next; + --statCounter.dist.updatees; + xfree(i); + } + optr = &i->next; + } +} + +void +distDelUpdatees(Updatee *u) +{ + Updatee *nu; + + for ( ; u; u = nu) { + nu = u->next; + --statCounter.dist.updatees; + xfree(u); + } +} + +void +distUpdateeChangeEntry(StoreEntry *entry, Updatee *u) +{ + entry->updatees = u; + for ( ; u; u = u->next) { + u->entry = entry; + } +} + + +/* Code to distribute contents of entry to updatees */ + +static void +distUpdate(Updatee *u) +{ + if (u->lastmod >= u->entry->lastmod) + /* Already has this version */ + return; + u->lastmod = u->entry->lastmod; /* Mark version being xferred */ + + ++statCounter.dist.updates; + kb_incr(&statCounter.dist.update_kbytes, u->entry->mem_obj->inmem_hi); + + u->p = putSend(u->entry, &u->saddr, (PF *) 0, 0, 1 /* dodist */); +} + +/* Distribute entry contents to anybody interested */ +void +distEntryUpdate(StoreEntry *entry, request_t *req, struct sockaddr_in *src) +{ + Updatee *u; + + ++statCounter.dist.content_upd; + + /* Open distribution socket to everybody interested */ + for (u = entry->updatees; u; u = u->next) { + assert(req); + /* Don't send updates to GET-requesting clients, + when we happen to know their identity. We do + know with other peers and on DIST reqs. */ + if (req->dist_type == DIST_DIST + && req->dist_port == u->saddr.sin_port + && req->my_addr.s_addr == u->saddr.sin_addr.s_addr) + continue; + + /* No problems here - send it on out */ + distUpdate(u); + } +} + + +/* Best-case object consistency support */ + +/* Change url from http: to httpdist1234: */ +/* Note: returns pointer to static buffer - contents change on next call. */ +char * +distifyUrl(char *url) +{ + char distbuf[48]; /* dist string holder */ + int plen, poff; + char *eop; + + /* Find the end of the protocol field */ + if ((eop = strchr(url, ':')) == NULL) + /* Give up if not of form http://... */ + return(url); + poff = eop - url; + + snprintf(distbuf, sizeof(distbuf), "dist%d", + ntohs(Config.Sockaddr.http->s.sin_port)); + plen = strlen(distbuf); + + /* Assemble the new URL */ + xmemcpy(urlbuf, url, poff); + xmemcpy(urlbuf + poff, distbuf, plen); + xstrncpy(urlbuf + poff + plen, url + poff, MAX_URL); + + return(urlbuf); +} + + +/* Report on push stats */ +void +statDistPrint(StoreEntry * sentry) +{ + statPutPrint(sentry); + + storeAppendPrintf(sentry, "\nDIST Statistics:\n\n"); + storeAppendPrintf(sentry, "DIST requests: %d\n", + statCounter.dist.dists); + storeAppendPrintf(sentry, "unDIST requests: %d\n", + statCounter.dist.undists); + storeAppendPrintf(sentry, "Updates Sent: %d\n", + statCounter.dist.updates); + storeAppendPrintf(sentry, "KBytes of Update Sent: %d\n", + statCounter.dist.update_kbytes); + storeAppendPrintf(sentry, "Content Updates: %d\n", + statCounter.dist.content_upd); + storeAppendPrintf(sentry, "Updatee Structures: %d\n", + statCounter.dist.updatees); + storeAppendPrintf(sentry, "Updatee Memory Consumption: %d\n", + statCounter.dist.updatees * sizeof(Updatee)); +} + + +/* Need this to make sure that reconfiguration gives correctly + updated FwdPushLinks */ +void +distInit() +{ + DistAllPeers = 0; + + cachemgrRegister("push", "Push Stats", + statDistPrint, 0, 1); +} + + Index: squid/src/enums.h diff -u squid/src/enums.h:1.37 squid/src/enums.h:1.27.2.7 --- squid/src/enums.h:1.37 Sun Jul 21 14:48:03 2002 +++ squid/src/enums.h Tue Sep 3 10:41:45 2002 @@ -48,6 +48,7 @@ LOG_TCP_MEM_HIT, LOG_TCP_DENIED, LOG_TCP_OFFLINE_HIT, + LOG_TCP_PUT, #if LOG_TCP_REDIRECTS LOG_TCP_REDIRECT, #endif @@ -56,6 +57,7 @@ LOG_UDP_DENIED, LOG_UDP_INVALID, LOG_UDP_MISS_NOFETCH, + LOG_UDP_PUT, LOG_ICP_QUERY, LOG_TYPE_MAX } log_type; @@ -92,6 +94,7 @@ ERR_FTP_UNAVAILABLE, ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */ ERR_TOO_BIG, + ERR_CONFLICT, TCP_RESET, ERR_MAX } err_type; @@ -437,6 +440,9 @@ PROTO_WHOIS, PROTO_INTERNAL, PROTO_HTTPS, +#if USE_HINT_CACHE + PROTO_ROUTE, +#endif PROTO_MAX } protocol_t; @@ -705,6 +711,7 @@ CBDATA_helper_stateful_server, CBDATA_HttpStateData, CBDATA_peer, + CBDATA_Pusher, CBDATA_ps_state, CBDATA_RemovalPolicy, CBDATA_RemovalPolicyWalker, @@ -723,6 +730,28 @@ VARY_CANCEL }; +enum { + DIST_NONE, + DIST_DIST, + DIST_UNDIST +}; + +#if USE_HINT_CACHE +enum HintCacheNet_State { + HC_uninitialized, + HC_filling, + HC_full, + HC_destroyed +}; + + +typedef enum HintCacheNeighborActionE { + NEIGHBOR_ADD, + NEIGHBOR_REMOVE +} NeighborAction; + +#endif /* USE_HINT_CACHE */ + /* * Store digest state enum */ Index: squid/src/globals.h diff -u squid/src/globals.h:1.17 squid/src/globals.h:1.14.2.4 --- squid/src/globals.h:1.17 Sun Jul 14 17:43:58 2002 +++ squid/src/globals.h Tue Sep 3 10:41:47 2002 @@ -159,6 +159,19 @@ extern RemovalPolicy *mem_policy; extern hash_table *proxy_auth_username_cache; /* NULL */ extern int incoming_sockets_accepted; +extern peer *DistAllPeers; +#if USE_HINT_CACHE +extern hash_table hint_table; +extern const URLKey INVALID_URL_KEY; +extern HintCacheDisk *HCDisk; +extern HintCacheNet *parentOutgoingA; +extern HintCacheNet *childrenOutgoingA; +extern HintCacheNet *neighborsOutgoing; +extern HintCacheDisk *hcDisk; +#if USE_DYNAMIC_HIERARCHY + +#endif /* USE_DYNAMIC_HIERARCHY */ +#endif /* USE_HINT_CACHE */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ extern char *WIN32_OS_string; /* NULL */ Index: squid/src/http.c diff -u squid/src/http.c:1.22 squid/src/http.c:1.17.2.6 --- squid/src/http.c:1.22 Sun Sep 1 09:30:42 2002 +++ squid/src/http.c Tue Sep 3 10:41:48 2002 @@ -45,9 +45,7 @@ static CWCB httpSendComplete; static CWCB httpSendRequestEntity; -static PF httpReadReply; static void httpSendRequest(HttpStateData *); -static PF httpStateFree; static PF httpTimeout; static void httpCacheNegatively(StoreEntry *); static void httpMakePrivate(StoreEntry *); @@ -55,7 +53,7 @@ static int httpCachableReply(HttpStateData *); static void httpMaybeRemovePublic(StoreEntry *, http_status); -static void +void httpStateFree(int fd, void *data) { HttpStateData *httpState = data; @@ -79,9 +77,11 @@ int httpCachable(method_t method) { - /* GET and HEAD are cachable. Others are not. */ - if (method != METHOD_GET && method != METHOD_HEAD) + /* GET, PUT, and HEAD are cachable. Others are not. */ + if (method != METHOD_GET && method != METHOD_HEAD && + method != METHOD_PUT) { return 0; + } /* else cachable */ return 1; } @@ -414,6 +414,7 @@ t = httpState->reply_hdr + k; } *t = '\0'; + httpState->body_remain -= hdr_len - (t - httpState->reply_hdr); httpState->reply_hdr_state++; assert(httpState->reply_hdr_state == 1); ctx = ctx_enter(entry->mem_obj->url); @@ -423,6 +424,9 @@ /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ httpReplyParse(reply, httpState->reply_hdr, hdr_len); + if (reply->content_length > 0) { + httpState->body_remain = reply->content_length + reply->hdr_sz; + } storeTimestampsSet(entry); /* Check if object is cacheable or not based on reply code */ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status); @@ -531,7 +535,7 @@ /* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ /* XXX this function is too long! */ -static void +void httpReadReply(int fd, void *data) { HttpStateData *httpState = data; @@ -610,7 +614,7 @@ fwdFail(httpState->fwd, err); httpState->eof = 1; comm_close(fd); - } else if (len == 0) { + } else if (len == 0 || len >= httpState->body_remain) { /* Connection closed; retrieval done. */ httpState->eof = 1; if (httpState->reply_hdr_state < 2) @@ -621,8 +625,26 @@ * we want to process the reply headers. */ httpProcessReplyHeader(httpState, buf, len); - fwdComplete(httpState->fwd); - comm_close(fd); + else + /* whole body is subtracted */ + httpState->body_remain -= len; + debug(50, 7) ("httpReadReply: body_remain = %d (len %d, state %d)\n", + httpState->body_remain, len, httpState->reply_hdr_state); + if (len > 0) { + storeAppend(entry, buf, len); + distEntryUpdate(entry, entry->mem_obj->request, + httpState->peer ? &httpState->peer->in_addr : 0); + } + if (entry->mem_obj->request && + entry->mem_obj->request->method == METHOD_PUT) { + putReplyAndClose(fd, entry); + debug(50, 8) ("httpReadReply: called putReplyAndClose\n"); + /* putReplyAndClose calls storeComplete() */ + } + else { + fwdComplete(httpState->fwd); + comm_close(fd); + } } else { if (httpState->reply_hdr_state < 2) { httpProcessReplyHeader(httpState, buf, len); @@ -639,7 +661,11 @@ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); } } + httpState->body_remain -= len; + debug(50, 8) ("httpReadReply: %d remain\n", httpState->body_remain); storeAppend(entry, buf, len); + distEntryUpdate(entry, entry->mem_obj->request, + httpState->peer ? &httpState->peer->in_addr : 0); if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* * the above storeAppend() call could ABORT this entry, @@ -904,9 +930,16 @@ http_state_flags flags) { const int offset = mb->size; + const char *url; + + url = strLen(request->urlpath) ? strBuf(request->urlpath) : "/"; + if (request->flags.distify) { + /* Ask other cache for dist */ + url = (const char *) distifyUrl((char *) url); + } + memBufPrintf(mb, "%s %s HTTP/1.0\r\n", - RequestMethodStr[request->method], - strLen(request->urlpath) ? strBuf(request->urlpath) : "/"); + RequestMethodStr[request->method], url); /* build and pack headers */ { HttpHeader hdr; @@ -983,6 +1016,7 @@ HttpStateData *httpState; request_t *proxy_req; request_t *orig_req = fwd->request; + peer *peer; debug(11, 3) ("httpStart: \"%s %s\"\n", RequestMethodStr[orig_req->method], storeUrl(fwd->entry)); @@ -991,13 +1025,15 @@ httpState->fwd = fwd; httpState->entry = fwd->entry; httpState->fd = fd; + httpState->body_remain = 0x7fffffff; if (fwd->servers) httpState->peer = fwd->servers->peer; /* might be NULL */ - if (httpState->peer) { + peer = httpState->peer; + if (peer) { proxy_req = requestCreate(orig_req->method, PROTO_NONE, storeUrl(httpState->entry)); - xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN); - proxy_req->port = httpState->peer->http_port; + xstrncpy(proxy_req->host, peer->host, SQUIDHOSTNAMELEN); + proxy_req->port = peer->http_port; proxy_req->flags = orig_req->flags; proxy_req->lastmod = orig_req->lastmod; httpState->request = requestLink(proxy_req); @@ -1008,8 +1044,12 @@ * We might end up getting the object from somewhere else if, * for example, the request to this neighbor fails. */ - if (httpState->peer->options.proxy_only) + if (peer->options.proxy_only) storeReleaseRequest(httpState->entry); + /* Use consistency protocol for this request */ + if (peer->options.dist) { + httpState->request->flags.distify = 1; + } #if DELAY_POOLS assert(delayIsNoDelay(fd) == 0); if (httpState->peer->options.no_delay) @@ -1107,3 +1147,32 @@ version->major = major; version->minor = minor; } + +/* + * Create an httpState parallel to an existing clientHttpRequest + * Assumption: http->entry is either zero or locked. + */ +HttpStateData * +httpStateFromClient(clientHttpRequest *http) +{ + HttpStateData *httpState; + + /* Make me an httpState */ + httpState = cbdataAlloc(HttpStateData); + + /* Fill in the blanks */ + httpState->entry = http->entry; + httpState->request = http->request; + httpState->body_remain = 0x7fffffff; + + assert(http->entry->lock_count >= 1); + /* Lock entry for a second time to reflect presence in httpState */ + /* XXX - can't use storeLockObject() because is NOT_IN_MEMORY (!!!) */ + httpState->entry->lock_count++; + assert(http->entry->lock_count >= 2); + + /* Register new request pointer */ + requestLink(httpState->request); + + return(httpState); +} Index: squid/src/icp_data.c diff -u /dev/null squid/src/icp_data.c:1.1.2.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/icp_data.c Mon Dec 10 14:22:24 2001 @@ -0,0 +1,414 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 83 ICP data transmission + * AUTHOR: Jon Kay, 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +static icpUdpData *UdpQueueHead = NULL; +static icpUdpData *UdpQueueTail = NULL; +icpQueue UdpCtlQ; +static List_Links icpFragQ; +ICPData_Stats icpdata_stats; + +static void icpRecvPush(int fd, struct sockaddr_in *from, icp_common_t *, + char *buf, int len); +static icpFragList *icpFragNew(char *buf, int off, int nextoff, int totlen, + icp_common_t *hdr, int isfirst); + +static icpFragList *icpFragFree(icpFragList *fl); + + +#define ICP_PUTLINE "PUT %s HTTP/1.0\r\n" + +/* Fragment and encapsulate stuff to be sent */ +void +icpSendData(int vfd, StoreEntry *entry, struct _pusher *p) +{ + int fd = theOutIcpConnection; + icpQueue *q = p->q; + int len, hdrlen, curlen; + struct icp_datab_s *dbhdr; + struct _http_reply *reply; + struct icp_data_s *dhdr; + char *firstline, *lnend; + icp_common_t *hdr; + char *buf, *tbuf; + icpUdpData *pktl; + int islast = 0; + int lchg, nllen, ollen; + + ++icpdata_stats.nsends; + debug(12, 5, "icpDataSend: vfd %d fd %d '%s'\n", vfd, fd, entry->key); + + reply = entry->mem_obj->reply; + curlen = entry->mem_obj->e_current_len; + if (p->objlen == 0) + p->objlen = reply->content_length + reply->hdr_sz; + + if (p->off < p->objlen) + /* Reregister handler */ + /* excess storeRegisters deregistered in putSendDone() call */ + storeRegister(entry, vfd, (PIF) icpSendData, p); + + while (p->off < curlen) { + /* Allocate 8k page, and put AppendUdp and ICP headers at beginning */ + buf = get_free_8k_page(); + hdr = (icp_common_t *) buf; + tbuf = (char *) &hdr[1]; + + /* Fill in ICP header */ + hdr->version = ICP_VERSION_CURRENT; + hdr->flags = 0; + hdr->pad = 0; + hdr->shostid = htonl(theOutICPAddr.s_addr); + + /* Is this the last fragment? */ + /* note: object_len == e_current_len iff storeComplete been called */ + islast = (p->off + 8000 >= entry->mem_obj->e_current_len + && (entry->object_len == curlen || p->objlen <= curlen)); + + if (p->off == 0) { + /* First fragment */ + p->reqnum = htonl(storeReqnum(entry, METHOD_PUT)); + hdr->opcode = ICP_OP_DATABEG; + dbhdr = (struct icp_datab_s *) tbuf; + tbuf = (char *) &dbhdr->db_data; + dbhdr->db_ttl = htonl(8); /* XXX*/ + dbhdr->db_ts = htonl(entry->lastmod); + hdrlen = sizeof(icp_common_t) + 12; + } + else { + /* Remaining fragments */ + hdr->opcode = islast ? ICP_OP_DATAEND : ICP_OP_DATA; + dhdr = (struct icp_data_s *) tbuf; + tbuf = (char *) &dhdr->d_data; + dhdr->d_offset = htonl(p->off); + hdrlen = sizeof(icp_common_t) + 4; + } + + storeClientCopy(entry, p->off, 8000, tbuf, &len, vfd); + + if (p->off == 0) { + /* Change the first line into a PUT line from a REPLY line */ + firstline = xmalloc(sizeof(ICP_PUTLINE) + strlen(entry->url)); + sprintf(firstline, ICP_PUTLINE, entry->url); + lnend = strchr(tbuf, '\n'); + if (lnend == NULL) { + /* Not enough stuff to send. */ + safe_free(firstline); + safe_free(buf); + storeUnregister(entry, vfd); + return; + } + while (lnend[1] == '\r' || lnend[1] == '\n') + ++lnend; + ollen = lnend - tbuf + 1; + nllen = strlen(firstline); + lchg = nllen - ollen; + memmove(tbuf + nllen, tbuf + ollen, len - ollen); + xmemcpy(tbuf, firstline, nllen); + p->objlen += lchg; + len += lchg; + dbhdr->db_size = htonl(p->objlen); + } + + p->off += len; + + hdr->length = hdrlen + len; + hdr->length = htons(hdr->length); + hdr->reqnum = p->reqnum; + + pktl = (icpUdpData *) xmalloc(sizeof(*pktl)); + pktl->address = q->dst; + pktl->msg = buf; + pktl->len = hdrlen + len; + pktl->start = current_time; + pktl->logcode = LOG_TAG_NONE; + pktl->proto = PROTO_NONE; + AppendUdp(q, pktl); + if (q->maxrate) + icpUdpReply(fd, q); + else + commSetSelect(fd, COMM_SELECT_WRITE, + (PF) icpUdpReply, (void *) q, 0); + + if (islast) + putSendDone(p->fd, p); + } + + if (p->off >= p->objlen) + storeUnregister(entry, vfd); +} + +void +icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr, char *buf, int len) +{ + struct icp_datab_s *dbhdr; + struct icp_data_s *dhdr; + icpFragList *fl, *fl2, *efl; + int off, datalen, objlen; + int ismerged; + char *nbuf; + + if (len < sizeof(icp_common_t)) { + debug(12, 0, "icpRecvData: packet shorter than headers (%d bytes)\n", len); + return; + } + if (len < hdr->length) { + debug(12, 0, "icpRecvData: incomplete packet (%d bytes out of %d bytes)\n", + len, hdr->length); + return; + } + + if (hdr->opcode == ICP_OP_DATABEG) { + dbhdr = (struct icp_datab_s *) buf; + buf = (char *) &dbhdr->db_data; + datalen = hdr->length - sizeof(icp_common_t) - 12; + off = 0; + objlen = ntohl(dbhdr->db_size); + if (objlen <= datalen) { + /* One packet long - no defrag needed. */ + nbuf = xmalloc(objlen + 1); + xmemcpy(nbuf, buf, objlen); + icpRecvPush(fd, src, hdr, nbuf, objlen); + return; + } + } + else if (hdr->opcode == ICP_OP_DATA || hdr->opcode == ICP_OP_DATAEND) { + /* A middle fragment */ + dhdr = (struct icp_data_s *) buf; + buf = (char *) &dhdr->d_data; + datalen = hdr->length - sizeof(icp_common_t) - 4; + off = ntohl(dhdr->d_offset); + objlen = 0; + } + else { + debug(12, 0, "icpRecvData: invalid opcode %d\n", hdr->opcode); + return; + } + + /* Find first fragment, with entry */ + debug(12, 5, "icpRecvData: id 0x%x defragging %d-%d\n", + hdr->reqnum, off, off + datalen); + ++icpdata_stats.nfrags; + efl = NULL; + ismerged = 0; + if (off == 0) { + assert(objlen); + fl = icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl); + LIST_FORALL2(&fl->links, icpFragList *, fl2); { + /* Look for more fragments */ + loopstart: + if (fl2->hdr.reqnum == hdr->reqnum && fl2->off == fl->nextoff) { + /* Consolidate this fragment */ + + if (fl2->off == 0) { + /* this is a dup */ + ++icpdata_stats.ndups; + icpFragFree(fl); + return; + } + + /* merge data */ + if (fl->nextoff < fl2->nextoff) + fl->nextoff = fl2->nextoff; + xmemcpy(fl->buf + fl2->off, fl2->buf, fl2->nextoff - fl2->off); + + /* delete old fragment */ + fl2 = icpFragFree(fl); + + goto loopstart; + } + } + } + else { + LIST_FORALL2(&icpFragQ, icpFragList *, fl) { + if (fl->hdr.reqnum == hdr->reqnum && fl->off == 0) { + if (!efl) + efl = fl; + if (fl->nextoff == off) { + /* Append to this packet */ + fl->nextoff += datalen; + xmemcpy(fl->buf + off, buf, datalen); + ismerged = 1; + if (fl->off == 0 && fl->objlen > 0 && fl->nextoff >= fl->objlen) { + /* Assembly complete*/ + icpRecvPush(fd, src, &fl->hdr, fl->buf, fl->objlen); + fl->buf = 0; + icpFragFree(fl); + return; + } + } + } + } + if (!ismerged) + icpFragNew(buf, off, off + datalen, objlen, hdr, (int) efl); + } +} + +static icpFragList * +icpFragNew(char *buf, int off, int nextoff, int objlen, + icp_common_t *hdr, int isfirst) +{ + icpFragList *fl; + int len; + + fl = (icpFragList *) xmalloc(sizeof *fl); + List_Insert(&fl->links, LIST_ATREAR(&icpFragQ)); + + len = (off ? nextoff - off : objlen + 1); + fl->buf = xmalloc(len + 1); + + xmemcpy(fl->buf, buf, nextoff - off); + fl->lasttime = squid_curtime; + fl->hdr = *hdr; + fl->off = off; + fl->nextoff = nextoff; + fl->objlen = objlen; + + return(fl); +} + +static icpFragList * +icpFragFree(icpFragList *fl) +{ + icpFragList *nfl; + +#if 0 + printf("icpFragFree: id 0x%x freeing %d-%d obj at 0x%x\n", + fl->hdr.reqnum, fl->off, fl->nextoff, fl->buf); +#endif + nfl = (icpFragList *) List_Next(&fl->links); + List_Remove(&fl->links); + if (fl->buf) + safe_free(fl->buf); + safe_free(fl); + return(nfl); +} + +static void +icpFragTimer() +{ + icpFragList *fl; +#if 0 /* JSKDEBUG */ + int nfrags = 0, mem = 0; +#endif + + eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL, + Config.icp_frag_tmo); + + LIST_FORALL2(&icpFragQ, icpFragList *, fl) { + loopstart: + if ((char *) fl != (char *) &icpFragQ) { +#if 0 /* JSKDEBUG */ + ++nfrags; + mem += fl->objlen + sizeof(*fl); +#endif + if (squid_curtime - fl->lasttime >= Config.icp_frag_tmo) { + ++icpdata_stats.ntmofrags; + fl = icpFragFree(fl); + goto loopstart; + } + } + } +#if 0 /* JSKDEBUG */ + printf("icpFragTimer: %d frags, for total of %d bytes used\n", + nfrags, mem); +#endif +} + + +static void +icpRecvPush(int fd, struct sockaddr_in *src, icp_common_t *hdr,char *buf, int len) +{ + icpStateData *icpState = xcalloc(sizeof(icpStateData), 1); + request_t *request = NULL; + int err; + + debug(12, 3, "icpRecvPush on fd %d: Hi!\n", fd); + ++icpdata_stats.nrecvs; + + /* Construct icpState */ + icpState->start = current_time; + icpState->inbuf = buf; + icpState->inbufsize = 8192; + icpState->header = *hdr; + icpState->peer = *src; + icpState->log_addr = src->sin_addr; + icpState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; + icpState->log_type = LOG_UDP_PUT; + icpState->me = *getMyAddr(); + icpState->me.sin_port = Config.Port.icp; + icpState->entry = NULL; + icpState->in_offset = len; + icpState->fd = comm_virtual_fd(); + + fd_note(fd, inet_ntoa(icpState->log_addr)); + comm_add_close_handler(icpState->fd, icpStateFree, (void *) icpState); + + err = parseHttpRequest(icpState); + icpState->inbuf[icpState->in_offset] = '\0'; /* Terminate the string */ + if (err == 1) { + if ((request = urlParse(icpState->method, icpState->url)) == NULL) { + debug(12, 0, "icpRecvPush: Invalid URL: %s\n", icpState->url); + return; + } + safe_free(icpState->log_url); + icpState->log_url = xstrdup(urlCanonicalClean(request)); + request->http_ver = icpState->http_ver; + if (!urlCheckRequest(request)) { + debug(12, 0, "icpRecvPush: Invalid request: %s\n"); + return; + } + icpState->request = requestLink(request); + + /* XXX - Uncomment to make acls work with icpdata pushes */ + /* Currently causes core dump, needs debugging */ + /* clientAccessCheck(icpState, clientAccessCheckDone);*/ + } + else if (err == 0) { + debug(12, 0, "icpRecvPush: got partial request\n"); + return; + } + else { /* err == -1 */ + debug(12, 0, "icpRecvPush: got invalid request\n"); + return; + } + + putRecv(icpState); +} + +void +icpDataInit() +{ + List_Init(&icpFragQ); + List_Init(&UdpCtlQ.links); + UdpCtlQ.nextsend.tv_sec = UdpCtlQ.nextsend.tv_usec = 0; + UdpCtlQ.maxrate = 0; + eventAdd("icpdata fragment timer", (EVH) icpFragTimer, NULL, + Config.icp_frag_tmo); +} Index: squid/src/icp_v2.c diff -u squid/src/icp_v2.c:1.6 squid/src/icp_v2.c:1.5.14.3 --- squid/src/icp_v2.c:1.6 Fri Aug 9 14:46:02 2002 +++ squid/src/icp_v2.c Tue Sep 3 10:41:49 2002 @@ -302,6 +302,14 @@ neighborsUdpAck(key, &header, &from); break; +#if USE_ICP_DATA + case ICP_OP_DATABEG: + case ICP_OP_DATA: + case ICP_OP_DATAEND: + icpRecvData(fd, &from, &header, buf + sizeof(header), len); + break; +#endif + case ICP_INVALID: case ICP_ERR: break; Index: squid/src/icp_v3.c diff -u squid/src/icp_v3.c:1.5 squid/src/icp_v3.c:1.4.44.3 --- squid/src/icp_v3.c:1.5 Fri Aug 9 14:46:02 2002 +++ squid/src/icp_v3.c Tue Sep 3 10:41:49 2002 @@ -143,6 +143,14 @@ neighborsUdpAck(key, &header, &from); break; +#if USE_ICP_DATA + case ICP_OP_DATABEG: + case ICP_OP_DATA: + case ICP_OP_DATAEND: + icpRecvData(fd, &from, &header, buf + sizeof(header), len); + break; +#endif + case ICP_INVALID: case ICP_ERR: break; Index: squid/src/main.c diff -u squid/src/main.c:1.36 squid/src/main.c:1.28.2.6 --- squid/src/main.c:1.36 Thu Aug 8 12:41:58 2002 +++ squid/src/main.c Tue Sep 3 10:41:51 2002 @@ -336,6 +336,7 @@ externalAclShutdown(); storeDirCloseSwapLogs(); errorClean(); + distInit(); enter_suid(); /* root to read config file */ parseConfigFile(ConfigFile); setEffectiveUser(); @@ -511,6 +512,12 @@ #if DELAY_POOLS delayPoolsInit(); #endif +#if USE_HINT_CACHE + hintCacheInit(); +#endif +#if USE_ICP_DATA + icpDataInit(); +#endif fwdInit(); } #if USE_WCCP @@ -626,6 +633,7 @@ eventInit(); /* eventInit() is required for config parsing */ storeFsInit(); /* required for config parsing */ authenticateSchemeInit(); /* required for config parsign */ + distInit(); /* Needed for fwdall list */ parse_err = parseConfigFile(ConfigFile); if (opt_parse_cfg_only) Index: squid/src/mem.c diff -u squid/src/mem.c:1.20 squid/src/mem.c:1.13.8.1 --- squid/src/mem.c:1.20 Sat Jul 20 18:06:07 2002 +++ squid/src/mem.c Tue Sep 3 10:41:52 2002 @@ -323,10 +323,6 @@ memInit(void) { int i; - - debug(13, 1) ("Memory pools are '%s'; limit: %.2f MB\n", - (Config.onoff.mem_pools ? "on" : "off"), toMB(mem_idle_limit)); - /* set all pointers to null */ memset(MemPools, '\0', sizeof(MemPools)); /* Index: squid/src/neighbors.c diff -u squid/src/neighbors.c:1.19 squid/src/neighbors.c:1.14.2.2 --- squid/src/neighbors.c:1.19 Wed Aug 28 14:45:44 2002 +++ squid/src/neighbors.c Tue Sep 3 10:41:53 2002 @@ -38,6 +38,8 @@ /* count mcast group peers every 15 minutes */ #define MCAST_COUNT_RATE 900 + + static int peerAllowedToUse(const peer *, request_t *); static int peerWouldBePinged(const peer *, request_t *); static void neighborRemove(peer *); Index: squid/src/protos.h diff -u squid/src/protos.h:1.59 squid/src/protos.h:1.41.2.7 --- squid/src/protos.h:1.59 Sat Jul 20 05:33:16 2002 +++ squid/src/protos.h Tue Sep 3 10:41:54 2002 @@ -180,6 +180,9 @@ extern void commCloseAllSockets(void); extern void checkTimeouts(void); extern int commDeferRead(int fd); +#if USE_ICP_DATA +extern int comm_virtual_fd(void); +#endif /* USE_ICP_DATA */ /* @@ -313,6 +316,9 @@ extern int httpAnonHdrDenied(http_hdr_type hdr_id); extern void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, http_state_flags); extern void httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor); +extern HttpStateData *httpStateFromClient(clientHttpRequest *http); +extern PF httpReadReply; +extern PF httpStateFree; extern const char *httpMakeVaryMark(request_t * request, HttpReply * reply); /* ETag */ @@ -532,6 +538,12 @@ int reqnum, int pad); extern int icpUdpSend(int, const struct sockaddr_in *, icp_common_t *, log_type, int); +#if USE_ICP_DATA +void icpSendData(int vfd, StoreEntry *entry, struct _pusher *p); +void icpRecvData(int fd, struct sockaddr_in *src, icp_common_t *hdr, + char *buf, int len); +void icpDataInit(); +#endif extern PF icpHandleUdp; extern PF icpUdpSendQueue; extern PF httpAccept; @@ -1102,7 +1114,8 @@ extern char *url_convert_hex(char *org_url, int allocate); extern char *url_escape(const char *url); -extern protocol_t urlParseProtocol(const char *); +extern protocol_t urlParseProtocol(const char *, u_short *, + int *); extern method_t urlParseMethod(const char *); extern void urlInitialize(void); extern request_t *urlParse(method_t, char *); @@ -1288,6 +1301,26 @@ extern void logfilePrintf(va_alist); #endif +/* put.c */ +void putRecv(clientHttpRequest *); +Pusher *putSend(StoreEntry *, struct sockaddr_in *, PF, void *, + int dodist); +void putSendDone(int fd, void *data); +void putReplyAndClose(int, StoreEntry *); +void statPutPrint(StoreEntry * sentry); + +/* dist.c */ +extern Updatee *distNewUpdatee(StoreEntry *entry, + struct in_addr host, u_short dport); +extern void distDelUpdatees(Updatee *u); +extern void distDelUpdatee(StoreEntry *entry, struct in_addr host, int dport); +extern void distUpdateeChangeEntry(StoreEntry *entry, Updatee *u); +extern void distEntryUpdate(StoreEntry *e, request_t *req, + struct sockaddr_in *peer); +extern char *distifyUrl(char *url); +extern void distInputDone(StoreEntry *); +void distInit(); + /* * Removal Policies */ @@ -1312,6 +1345,146 @@ */ extern StatCounters *snmpStatGet(int); + +#if USE_HINT_CACHE +/* Hint Cache Interface */ +/* open existing cache; return nonzero on error */ +int hintCacheInit(); +void hintCacheCreate(); /* create new cache */ +void hintCacheDestroy(); +void hintCacheInformLocalCopy(StoreEntry *); /* tell hierarchy I have a copy */ +void hintCacheInvalLocalCopy(StoreEntry *); /* say I don't have a copy */ +int hintCacheActive(); /* Ask hint cache if it is operational. */ +struct sockaddr_in *hintCachefindNearest(char *url, struct sockaddr_in *); + +void hintCacheNodeKeyInit(NodeKey *k, const struct sockaddr_in *addrP); +int hintCacheNodeKeyCompare(const NodeKey *k1, const NodeKey *k2); +struct sockaddr_in hintCacheNodeKeyGetAddr(const NodeKey *k); +HintCacheKey hintCacheNodeKeyKey(const struct sockaddr_in *addrP); + +void hintCacheEntryInit(HintCacheEntry *, URLKey, struct sockaddr_in *, + unsigned int mtime); +int hintCacheEntryCompare(HintCacheEntry *e1, HintCacheEntry *e2); +void hintCacheEntryInitNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry); +void hintCacheEntryLocalFormatNet(HintCacheEntryNet *mungedEntry, HintCacheEntry *entry); + +int hintCacheUpdateCompare(HintCacheUpdate *u1, HintCacheUpdate *u2); +void hintCacheUpdateInit(HintCacheUpdate *, int action, HintCacheEntry *, int hopcount); + +void hintCacheUpdateInitNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update); +void hintCacheUpdateLocalFormatNet(HintCacheUpdateNet *mungedUpdate, HintCacheUpdate *update); +int hintCacheURLKeyCompare(URLKey *u1, URLKey *u2); +StoreEntry *hintCacheStoreGet(URLKey urlkey); + + +/* Hint Cache Disk */ +void hintCacheDiskInit(HintCacheDisk *d, char *diskPath); +void hintCacheDiskClose(HintCacheDisk *d); +void hintCacheDiskCreateFile(char *hcPath, int size, int associativity); +void hintCacheDiskInformLocal(HintCacheDisk *d, URLKey key, unsigned mtime); +void hintCacheDiskInvalLocal(HintCacheDisk *d, URLKey key, unsigned mtime); +void hintCacheDiskPrefetch(HintCacheDisk *d, HintCacheUpdate *uArray, int nupdates); +int hintCacheDiskNetInvalRecord(HintCacheDisk *d, HintCacheEntry *target, HintCacheEntry *survivor); +int hintCacheDiskUpdateIfCloser(HintCacheDisk *d, HintCacheEntry *new); +int hintCacheDiskFindNearest(HintCacheDisk *d, URLKey key, HintCacheEntry *match); +void hintCacheDiskDeleteHintCache(); + +long long unsigned hintCacheEndian_llNetToMachine(long long unsigned net); +long long unsigned hintCacheEndian_llMachineToNet(long long unsigned mach); +void hintCacheEndian_selfTest(void); + +void hintCacheInitNet(HintCacheNet *n); +int hintCacheNetIsInitialized(void); + void hintCacheNetDestroy(HintCacheNet *n); +void hintCacheNetEnqueue(HintCacheNet *, int action, + HintCacheEntry *, int hopcount); +int hintCacheNetBytesReady(HintCacheNet *n); +void hintCacheNetComplete(HintCacheNet *n); +void hintCacheNetDone(HintCacheNet *n); +void hintCacheNetSendTo(HintCacheNet *, struct sockaddr_in *); +void hintCacheNetSendJoin(); +void hintCacheNetDataArrives(char *data, int len, HintCacheNetHeader *hdr, + struct sockaddr_in *source); +void hintCacheNetSetTestMode(HintCacheNet *n); +int hintCacheNetGetTestCount(HintCacheNet *n); + +void hintCachePropLocalAction(StoreEntry *, int action); +void hintCachePropHandleInvalToChild(HintCacheUpdate *update, + struct sockaddr_in *src, int local); +void hintCachePropHandleInformToChild(HintCacheUpdate *update, + struct sockaddr_in *src, int local) ; +void hintCachePropHandleInvalToParent(HintCacheUpdate *update, + struct sockaddr_in *src, int local); +void hintCachePropHandleInformToParent(HintCacheUpdate *update, + struct sockaddr_in *src, int local); + +void hintCacheNodelistInit(); /* constructor */ +void hintCacheNodelistDestroy(); /* destructor */ +void hintCacheNodelistSelfTest(); +void hintCacheNodelistLocalJoin(); /* I do a join */ +void hintCacheNodelistLocalLeave(); /* I do a leave */ +int hintCacheNodelistMyStatus(); /* Am I in or out? */ +void hintCacheNodelistNetJoin(struct sockaddr_in *sin, int hops, long long timeNS); +void hintCacheNodelistNetLeave(struct sockaddr_in *sin, int hops, long long timeNS); +void hintCacheNodelistIterStart(HintCacheNodeListIter *iter); +int hintCacheNodelistIterCheck(HintCacheNodeListIter iter); +void hintCacheNodelistIterNext(HintCacheNodeListIter *iter); +int hintCacheNodelistIterGetAddr(HintCacheNodeListIter iter, + struct sockaddr_in *ret); + +void hintCacheHierUpdateMembershipNeighbor(struct sockaddr_in *neighbor, + NeighborAction); +void hintCacheHierInit(); +void hintCacheHierDestroy(); +int hintCacheHierCompareDistanceFromMe(struct in_addr new, struct in_addr old); +void hintCacheHierNewNode(struct sockaddr_in *sin, int hops, long long time); +void hintCacheHierDelNode(struct sockaddr_in *sin, int hops, long long time); +int hintCacheHierCheckIfParent(URLKey key, struct sockaddr_in *candidate); +int hintCacheHierCheckIfChild(struct sockaddr_in *candidate); +void hintCacheHierAddChild(struct sockaddr_in *child); +void hintCacheHierRemoveChild(struct sockaddr_in *child); +int hintCacheHierNChildrenQs(); +int hintCacheHierChildQIndex(URLKey *key, int iAmRoot, int *amILeaf); +int hintCacheHierGetChildAddrs(int qIndex, struct sockaddr_in **retAddr); +int hintCacheHierNParentQs(); +int hintCacheHierParentQIndex(URLKey *key, int *amIRoot); +int hintCacheHierGetParentAddr(int index, struct sockaddr_in *retAddr); +int hintCacheHierSendToParent(struct sockaddr_in *src, HintCacheUpdate *update, + int msgtype); +int hintCacheHierSendToSiblings(struct sockaddr_in *src, HintCacheUpdate *update, + int msgtype, int siblingtype); + +#ifdef USE_DYNAMIC_HIERARCHY +/* Plaxton Dynamic Hierarchy algorithm */ +void plaxtonInit(int bitsPerLevel); +void plaxtonDestroy(); +int plaxtonChildQIndex(URLKey *key, int iAmRoot, int *amILeaf); +int plaxtonNChildrenQsI(); +int plaxtonGetChildAddrs(int qIndex, struct sockaddr_in **retAddrAP); +int plaxtonNParentQs(); +int plaxtonParentQIndex(URLKey *key, int *amIRoot); +int plaxtonGetParentAddr(int index, struct sockaddr_in *retAddr); +/* + * Callbacks when nodes added/removed/change distance + */ +void plaxtonAddNode(struct sockaddr_in *newNode); +void plaxtonRemoveNode(struct sockaddr_in *goneNode); +void plaxtonChangeDistance(struct sockaddr_in *changeDistNode); +int plaxtonCheckIfParent(URLKey key, struct sockaddr_in *candidate); +int plaxtonCheckIfChild(struct sockaddr_in *candidate); +void plaxtonAddChild(struct sockaddr_in *child); +void plaxtonRemoveChild(struct sockaddr_in *child); +int plaxtonMatchBits(HintCacheKey k1, HintCacheKey k2); +HintCacheKey plaxtonMyNodeKey(); + +extern int Plaxton_BucketsPerLevel; +extern HintCacheNet *Plaxton_parentOutgoingA; +extern HintCacheNet *Plaxton_childrenOutgoingA; +extern HintCacheNet *Plaxton_neighborsOutgoing; +#endif /* USE_DYNAMIC_HIERARCHY / Plaxton algorithm */ + +#endif /* USE_HINT_CACHE */ + /* Vary support functions */ int varyEvaluateMatch(StoreEntry * entry, request_t * req); Index: squid/src/put.c diff -u /dev/null squid/src/put.c:1.1.2.7 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/put.c Tue Sep 3 10:41:55 2002 @@ -0,0 +1,457 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * DEBUG: section 81 PUT transmission and reception + * AUTHOR: Jon Kay, 1997 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +#define PUT_REPLY_HDR() "HTTP/1.0 200 OK\r\n" + +#define PUT_DELETE_GAP (1<<18) + +static PF putRecvFree; +static void putRecvError(clientHttpRequest *http, + err_type error, http_status entry); +static void putProcessHeader(HttpStateData *, clientHttpRequest *); +static void putSendWrite(void *data, char *buf, ssize_t len); +static CNCB putConnected; +static CWCB putSendSent; + +/* + * Code for dealing with incoming PUT requests + */ +void +putRecv(clientHttpRequest *http) +{ + request_t *request = http->request; + ConnStateData *conn = http->conn; + StoreEntry *entry, *oentry; + int lastmod, olastmod = -1; + HttpStateData *httpState; + request_flags rflags; + HttpReply *reply; + peer *p; + + http->request->flags.cachable = 1; + if (http->log_type != LOG_UDP_PUT) + http->log_type = LOG_TCP_PUT; + http->out.offset = 0; + + oentry = storeGetPublic(http->uri, request->method); + if (oentry) { + olastmod = oentry->lastmod; + storeSetPrivateKey(oentry); + } + + /* Create private, blank entry */ + *(unsigned int *) &rflags = 0; + rflags.cachable = 1; + entry = storeCreateEntry(http->uri, http->uri, rflags, request->method); + + http->entry = entry; + + /* Need a request pointer in the mem_obj */ + requestLink(http->request); + entry->mem_obj->request = request; + + debug(81, 4) ("putRecv: %s for '%s'\n", log_tags[http->log_type], + http->uri); + + /* Update timestamp */ + storeTimestampsSet(entry); + + /* Create an HTTP context from client_side info */ + assert(http->entry->lock_count >= 1 && http->entry->lock_count < 200); + httpState = httpStateFromClient(http); + assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200); + httpState->entry = entry; + /* Prepare to reply and free httpState if PUT succeeds. */ + comm_add_close_handler(conn->fd, putRecvFree, httpState); + + assert(http->entry->lock_count >= 2 && http->entry->lock_count < 200); + /* Parse the headers */ + putProcessHeader(httpState, http); + reply = entry->mem_obj->reply; + + /* Update the timestamp */ + lastmod = entry->mem_obj->reply->last_modified; + if (lastmod > -1) { + if (lastmod < olastmod) { + /* We do not accept old versions */ + ++statCounter.put.conflicts; + putRecvError(http, ERR_CONFLICT, HTTP_CONFLICT); + if (oentry) + storeSetPublicKey(oentry); + /* putRecvFree will clean up on fd close */ + return; + } + /* Note: it's OK to overwrite the same version. It just won't be + propagated. */ + entry->lastmod = lastmod; + } + else + /* Make it clear the version has changed even if no lastmod */ + entry->lastmod = olastmod + 1; + + if (oentry) { + /* This PUT request is good to go in. + * Lose the old entry. */ + distUpdateeChangeEntry(entry, oentry->updatees); + oentry->updatees = 0; + storeRelease(oentry); + } + + /* Make sure dist knows about the sender, and distribute the update */ + if (request->dist_type == DIST_DIST) + distNewUpdatee(entry, conn->peer.sin_addr, request->dist_port); + else if (request->dist_type == DIST_UNDIST) + distDelUpdatee(entry, conn->peer.sin_addr, request->dist_port); + distEntryUpdate(entry, request, &conn->peer); + + /* fwdpush support */ + if (http->log_type == LOG_TCP_PUT) { + for (p = DistAllPeers; p; p = p->fwdpush) { +#if USE_ICP_DATA + if (p->options.icpdata) { + putSend(entry, &p->in_addr, NULL, NULL, P_ICPDATA, p->icp_data_q); + } + else { +#endif + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + sin.sin_addr = p->in_addr.sin_addr; + sin.sin_port = htons(p->http_port); + putSend(entry, &sin, NULL, NULL, 0); +#if USE_ICP_DATA + } +#endif + } + } + + /* Update stats */ + ++statCounter.put.ins; + + /* XXX - Can we use httpReplyParse to simplify this? */ + + /* httpReadReply reads msgs with bodies */ + if (entry->mem_obj->inmem_hi < reply->content_length + reply->hdr_sz) { + httpReadReply(conn->fd, httpState); + } + else + putReplyAndClose(conn->fd, entry); +} + + +/* Process PUT header. */ +static void +putProcessHeader(HttpStateData *httpState, clientHttpRequest *client) +{ + static char replline[] = "HTTP/1.0 200 OK"; + char *hdr = client->hdr_str; + ConnStateData *conn = client->conn; + int hdrlen; + int bodylen = conn->in.offset; /* !yep! */ + char *eol; + + /* First change the PUT first line to a reply first line */ + eol = strchr(hdr, '\r'); + eol[0] = '\0'; + strcpy(hdr, replline); + memset(hdr + sizeof(replline) - 1, ' ', eol - hdr - sizeof(replline) + 1); + eol[0] = '\r'; + + hdrlen = strlen(hdr); + + httpProcessReplyHeader(httpState, hdr, hdrlen); + debug(81, 6) ("putProcessHeader: need %d bytes\n", httpState->body_remain); + + /* store header and start of data */ + storeAppend(client->entry, hdr, hdrlen); + if (bodylen > 0) + storeAppend(client->entry, conn->in.buf, bodylen); + + httpState->body_remain -= client->entry->mem_obj->inmem_hi; + debug(81, 6) ("putProcessHeader: got %d bytes, %d remain\n", + hdrlen + bodylen, httpState->body_remain); +} + +void +putClose(int fd, char *buf, size_t size, int errflag, void *data) +{ + comm_close(fd); /* close fd and call putRecvFree */ +} + +void +putReplyAndClose(int fd, StoreEntry *entry) +{ + storeComplete(entry); + + /* PUT succeeded, acknowledge this. */ + if (entry->mem_obj->reply->sline.status == 200) { + debug(81, 6) ("putReplyAndClose: replying on %d\n", fd); + comm_write(fd, PUT_REPLY_HDR(), sizeof(PUT_REPLY_HDR()), + putClose, 0, 0); + } + else { + /* Already aborted, hopefully with error msg */ + debug(81, 2) ("putReplyAndClose: not replying - code = %d\n", + entry->mem_obj->reply->sline.status); + comm_close(fd); /* close fd and call putRecvFree */ + } +} + +static void +putRecvFree(int fd, void *data) +{ + HttpStateData *httpState = data; + StoreEntry *entry = httpState->entry; + + kb_incr(&statCounter.put.kbytes_in, entry->mem_obj->inmem_hi); + + httpStateFree(fd, httpState); + assert(entry->lock_count >= 1); + /* Last unlock will be from httpRequestFree */ +} + +static void +putRecvError(clientHttpRequest *http, + err_type error, http_status status) +{ + ErrorState *err; + + http->log_type = LOG_TCP_DENIED; + err = errorCon(error, status); + err->request = requestLink(http->request); + err->src_addr = http->conn->peer.sin_addr; + http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); + errorAppendEntry(http->entry, err); +} + + +/* Output PUTs */ + +/* + * Make up and send a PUT to a given location. + * + * The sockaddr_in does not have to persist when + * the call completes. + */ +Pusher * +putSend(StoreEntry *entry, struct sockaddr_in *saddr, + PF *handler, void *arg, int dodist) +{ + struct in_addr nobody; + Pusher *p; + int fd; + + /* Allocate memory for buffer and state tracking */ + storeLockObject(entry); /* Yes, we need this, even on top of StoreClient. */ + p = cbdataAlloc(Pusher); + p->hdr.sc = storeClientListAdd(entry, p); + p->hdr.flags.disting = dodist; + p->hdr.flags.active = 1; + p->hdr.off = 0; + p->hdr.objlen = 0; + p->hdr.entry = entry; + p->hdr.handler = handler; + p->hdr.arg = arg; +#if USE_ICP_DATA + if (flags & P_ICPDATA) { + p->hdr.fd = comm_virtual_fd(); + p->hdr.q = q; + q->dst = *saddr; + icpSendData(p->hdr.fd, entry, p); + return(p); + } + else + p->hdr.q = 0; +#endif + + /* Need to create and connect a PUT socket */ + nobody.s_addr = INADDR_ANY; + p->hdr.fd = fd = comm_open(SOCK_STREAM, 0, nobody, 0, COMM_NONBLOCKING, "put"); + if (fd == COMM_ERROR) { + debug(11, 1) ("putSend: Could not create new socket.\n"); + putSendDone(-1, p); + return(0); + } + + /* Deal with socket closing */ + comm_add_close_handler(fd, putSendDone, p); + + ++statCounter.put.outs; + + /* Connect to this updatee */ + strcpy(p->hdr.hname, inet_ntoa(saddr->sin_addr)); + commConnectStart(fd, p->hdr.hname, ntohs(saddr->sin_port), + putConnected, p); + + return(p); +} + +/* Update given updatee on contents of entry */ +static void +putConnected(int fd, int commstat, void *data) +{ + Pusher *p = (Pusher *) data; + StoreEntry *entry = p->hdr.entry; + char *url; + + if (commstat == COMM_ERROR) { + /* XXX - this should be more sophisticated */ + debug(11, 1) ("putConnected: Could not connect to %s\n", p->hdr.hname); + putSendDone(fd, p); + return; + } + + /* Figure out what URL to use */ + url = entry->mem_obj->url; + if (p->hdr.flags.disting) { + url = distifyUrl(url); + } + + /* Compose header */ + snprintf(p->data, sizeof(p->data), "PUT %s HTTP/1.0\r\n", url); + p->hdr.off = -strlen(p->data); + + /* Write object asynchronously, starting with header */ + comm_write(fd, p->data, strlen(p->data), putSendSent, p, 0); +} + +/* Xfer data from mem_obj to updatee */ +/* XXX - duplication with icpSendMoreData, etc. */ +static void +putSendSent(int fd, char *obuf, size_t size, int errflag, void *data) +{ + Pusher *p = (Pusher *) data; + StoreEntry *entry = p->hdr.entry; + + debug(53, 5) ("putSendSent: FD %d '%s'\n", fd, entry->mem_obj->url); + + if (errflag) { + debug(53, 3) ("putSendSent: write failed, errno %d\n", errno); + putSendDone(fd, p); + return; + } + + p->hdr.off += size; + + if (p->hdr.off >= entry->mem_obj->inmem_hi) { + /* We've sent everything we've seen so far */ + if (entry->mem_obj->object_sz == entry->mem_obj->inmem_hi) { + /* We've seen all we're gonna see of this version */ + /* note: object_len == inmem_hi iff storeComplete been called */ + putSendDone(fd, p); + return; + } + } + + storeClientCopy(p->hdr.sc, entry, p->hdr.off, + sizeof(p->data) - p->hdr.off, + p->data, putSendWrite, p); +} + +/* xlate storeClientCopy calling conventions to comm_write ones */ +static void +putSendWrite(void *data, char *buf, ssize_t len) +{ + Pusher *p = (Pusher *) data; + int skipped; + char *tbuf; + + /* + * Skip over the first line, if this is the first call to putSendSent + * and that first line starts with HTTP/1.x. That would be the first + * line in a server reply, and is incorrect in a PUT request. + */ + if (p->hdr.off == 0) { + tbuf = strchr(p->data, '\n'); + if (!tbuf) + /* Malformatted or not enough data present yet. + * Either way, don't propagate this message. */ + return; + + while (*++tbuf == '\r') + ; + skipped = tbuf - p->data; + p->hdr.off += skipped; + len -= skipped; + buf += skipped; + } + else + tbuf = p->data; + + /* Do the work. */ + comm_write(p->hdr.fd, buf, len, putSendSent, p, 0); +} + +/* Send the object's data */ +void +putSendDone(int fd, void *data) +{ + Pusher *p = data; + StoreEntry *entry = p->hdr.entry; + + if (!(p->hdr.flags.active)) + return; + p->hdr.flags.active = 0; + + if (p->hdr.handler) + (*p->hdr.handler)(fd, p->hdr.arg); + + kb_incr(&statCounter.put.kbytes_out, p->hdr.off); + storeUnregister(p->hdr.sc, entry, (void *) fd); + storeUnlockObject(entry); + + /* Free 8k buffer and pusher state along with it */ + cbdataFree(p); + + /* Don't close if ICP - ICP sends via theIcpOutConnection, + * which we cannot afford to close. */ + if (fd != -1) + comm_close(fd); +} + + +/* Report on push stats */ +void +statPutPrint(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "PUT Statistics:\n\n"); + storeAppendPrintf(sentry, "PUTs Sent: %d\n", + statCounter.put.outs); + storeAppendPrintf(sentry, "PUT KBytes Sent: %d\n", + (int) statCounter.put.kbytes_out.kb); + storeAppendPrintf(sentry, "PUTs Received: %d\n", + statCounter.put.ins); + storeAppendPrintf(sentry, "PUT KBytes Received: %d\n", + (int) statCounter.put.kbytes_in.kb); + storeAppendPrintf(sentry, "Stale Objects Received: %d\n", + statCounter.put.conflicts); +} Index: squid/src/squid.h diff -u squid/src/squid.h:1.19 squid/src/squid.h:1.13.2.3 --- squid/src/squid.h:1.19 Sun Sep 1 09:30:42 2002 +++ squid/src/squid.h Tue Sep 3 10:41:56 2002 @@ -410,6 +410,10 @@ #include "snprintf.h" #endif +#if HAVE_SYS_MMAN_H +#include +#endif + #define XMIN(x,y) ((x)<(y)? (x) : (y)) #define XMAX(a,b) ((a)>(b)? (a) : (b)) Index: squid/src/stat.c diff -u squid/src/stat.c:1.17 squid/src/stat.c:1.13.2.4 --- squid/src/stat.c:1.17 Sun Apr 7 17:38:18 2002 +++ squid/src/stat.c Tue Sep 3 10:41:57 2002 @@ -816,6 +816,32 @@ storeAppendPrintf(sentry, "aborted_requests = %f/sec\n", XAVG(aborted_requests)); + storeAppendPrintf(sentry, "dist.dists = %f/sec\n", + XAVG(dist.dists)); + storeAppendPrintf(sentry, "dist.undists = %f/sec\n", + XAVG(dist.undists)); + storeAppendPrintf(sentry, "dist.updates = %f/sec\n", + XAVG(dist.updates)); + storeAppendPrintf(sentry, "dist.update_kbytes = %f/sec\n", + XAVG(dist.update_kbytes.kb)); + storeAppendPrintf(sentry, "dist.content_upd = %f/sec\n", + XAVG(dist.content_upd)); + storeAppendPrintf(sentry, "dist.updatees = %f/sec\n", + XAVG(dist.updatees)); + storeAppendPrintf(sentry, "dist.updatees = %f/sec\n", + XAVG(dist.updatees * sizeof(Updatee))); + + storeAppendPrintf(sentry, "put.outs = %f/sec\n", + XAVG(put.outs)); + storeAppendPrintf(sentry, "put.kbytes_out = %f/sec\n", + XAVG(put.kbytes_out.kb)); + storeAppendPrintf(sentry, "put.ins =: %f\n", + XAVG(put.ins)); + storeAppendPrintf(sentry, "put.kbytes_in = %f/sec\n", + XAVG(put.kbytes_in.kb)); + storeAppendPrintf(sentry, "put.conflicts = %f/sec\n", + XAVG(put.conflicts)); + #if USE_POLL storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.polls)); #endif @@ -1200,6 +1226,32 @@ f->swap.files_cleaned); storeAppendPrintf(sentry, "aborted_requests = %d\n", f->aborted_requests); + + storeAppendPrintf(sentry, "dist.dists = %d\n", + f->dist.dists); + storeAppendPrintf(sentry, "dist.undists = %d\n", + f->dist.undists); + storeAppendPrintf(sentry, "dist.updates = %d\n", + f->dist.updates); + storeAppendPrintf(sentry, "dist.update_kbytes = %d\n", + (int) f->dist.update_kbytes.kb); + storeAppendPrintf(sentry, "dist.content_upd = %d\n", + f->dist.content_upd); + storeAppendPrintf(sentry, "dist.updatees = %d\n", + f->dist.updatees); + storeAppendPrintf(sentry, "dist.updatees = %d\n", + f->dist.updatees * sizeof(Updatee)); + + storeAppendPrintf(sentry, "put.outs = %d\n", + f->put.outs); + storeAppendPrintf(sentry, "put.kbytes_out = %d\n", + (int) f->put.kbytes_out.kb); + storeAppendPrintf(sentry, "put.ins =: %d\n", + f->put.ins); + storeAppendPrintf(sentry, "put.kbytes_in = %d\n", + (int) f->put.kbytes_in.kb); + storeAppendPrintf(sentry, "put.conflicts = %d\n", + f->put.conflicts); } void Index: squid/src/store.c diff -u squid/src/store.c:1.17 squid/src/store.c:1.16.2.3 --- squid/src/store.c:1.17 Thu Aug 15 11:14:04 2002 +++ squid/src/store.c Tue Sep 3 10:41:57 2002 @@ -179,6 +179,8 @@ if (e->mem_obj) destroy_MemObject(e); storeHashDelete(e); + if (e->updatees) + distDelUpdatees(e->updatees); assert(e->hash.key == NULL); memFree(e, MEM_STOREENTRY); } @@ -192,12 +194,22 @@ e, storeKeyText(key)); e->hash.key = storeKeyDup(key); hash_join(store_table, &e->hash); +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) { + e->hchhash.key = e->hash.key; + hash_join(cache_table, &e->hchash); + } +#endif } static void storeHashDelete(StoreEntry * e) { hash_remove_link(store_table, &e->hash); +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) + hash_remove_link(hint_table, &e->hchash); +#endif storeKeyFree(e->hash.key); e->hash.key = NULL; } @@ -710,6 +722,9 @@ assert(e->mem_obj->nclients == 0); return; } +#if USE_HINT_CACHE + hintCacheInformLocalCopy(e->mem_obj->url, e); +#endif e->mem_obj->object_sz = e->mem_obj->inmem_hi; e->store_status = STORE_OK; assert(e->mem_status == NOT_IN_MEMORY); @@ -873,6 +888,11 @@ destroy_StoreEntry(e); } } + +#if USE_HINT_CACHE + hintCacheInvalLocalCopy(e); +#endif + storeLog(STORE_LOG_RELEASE, e); if (e->swap_filen > -1) { storeUnlink(e); @@ -1000,6 +1020,20 @@ storeInitHashValues(); store_table = hash_create(storeKeyHashCmp, store_hash_buckets, storeKeyHashHash); +#if USE_HINT_CACHE + /* + * Need to be able to look up objects from hint + * cache key so we can invalidate obsolete objects + * based on hint cache updates. + * Note: the hint cache key is just the first 8 bytes + * of the 16-byte cache key, so storeKeyHashHash will + * always work. Although, right now, sKHH only looks + * at the first 32 bits anyway, giving double protection. + */ + if (HINT_CACHE_ACTIVE()) + hint_table = hash_create(hintCacheURLKeyCompare, + store_hash_buckets, storeKeyHashHash); +#endif mem_policy = createRemovalPolicy(Config.memPolicy); storeDigestInit(); storeLogOpen(); @@ -1056,6 +1090,12 @@ if (store_digest) cacheDigestDestroy(store_digest); #endif +#if USE_HINT_CACHE + if (HINT_CACHE_ACTIVE()) { + hashFreeMemory(hint_table); + hint_table = NULL; + } +#endif store_digest = NULL; } Index: squid/src/store_key_md5.c diff -u squid/src/store_key_md5.c:1.6 squid/src/store_key_md5.c:1.6.24.1 --- squid/src/store_key_md5.c:1.6 Fri Apr 13 17:31:02 2001 +++ squid/src/store_key_md5.c Fri Dec 14 00:00:37 2001 @@ -99,6 +99,11 @@ assert(id > 0); debug(20, 3) ("storeKeyPrivate: %s %s\n", RequestMethodStr[method], url); + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (method == METHOD_PUT) + method = METHOD_GET; + MD5Init(&M); MD5Update(&M, (unsigned char *) &id, sizeof(id)); MD5Update(&M, (unsigned char *) &method, sizeof(method)); @@ -113,6 +118,11 @@ static cache_key digest[MD5_DIGEST_CHARS]; unsigned char m = (unsigned char) method; MD5_CTX M; + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (m == METHOD_PUT) + m = METHOD_GET; + MD5Init(&M); MD5Update(&M, &m, sizeof(m)); MD5Update(&M, (unsigned char *) url, strlen(url)); @@ -133,6 +143,11 @@ unsigned char m = (unsigned char) method; const char *url = urlCanonical(request); MD5_CTX M; + + /* PUT goes to same namespace as GETs do, so treat them alike here */ + if (m == METHOD_PUT) + m = METHOD_GET; + MD5Init(&M); MD5Update(&M, &m, sizeof(m)); MD5Update(&M, (unsigned char *) url, strlen(url)); Index: squid/src/structs.h diff -u squid/src/structs.h:1.65 squid/src/structs.h:1.47.2.7 --- squid/src/structs.h:1.65 Sun Sep 1 09:30:42 2002 +++ squid/src/structs.h Tue Sep 3 10:41:58 2002 @@ -338,6 +338,12 @@ #endif +#if USE_HINT_CACHE +struct _URLKey { + HintCacheKey key; +}; +#endif + #if DELAY_POOLS struct _delaySpec { int restore_bps; @@ -588,6 +594,11 @@ int ie_refresh; int vary_ignore_expire; int pipeline_prefetch; +#if USE_HINT_CACHE + int hint_cache_listen; + int hint_cache_advertise; + int hint_cache_use_mmap; +#endif int check_hostnames; int via; } onoff; @@ -681,6 +692,16 @@ int unclean_shutdown; } SSL; #endif +#if USE_HINT_CACHE + struct { + char *cache_file; + int size; + int assoc; + int intvl; + int join_intvl; + int holddown; + } Hints; +#endif wordlist *ext_methods; struct { int high_rptm; @@ -979,6 +1000,7 @@ int fd; http_state_flags flags; FwdState *fwd; + int body_remain; }; struct _icpUdpData { @@ -1062,6 +1084,7 @@ } out; HttpHdrRangeIter range_iter; /* data for iterating thru range specs */ size_t req_sz; /* raw request size on input, not current request size */ + char *hdr_str; /* Copy of headers */ StoreEntry *entry; StoreEntry *old_entry; log_type log_type; @@ -1281,6 +1304,13 @@ unsigned int no_delay:1; #endif unsigned int allow_miss:1; + unsigned int dist:1; +#if USE_ICP_DATA + unsigned int icpdata:1; +#endif +#if USE_HINT_CACHE + unsigned int nohint:1; +#endif #if USE_CARP unsigned int carp:1; #endif @@ -1319,6 +1349,8 @@ char *login; /* Proxy authorization */ time_t connect_timeout; int max_conn; + peer *fwdpush; /* next peer on FwdPushLinks */ + int max_rate; /* Max push rate to this peer */ }; struct _net_db_name { @@ -1547,6 +1579,10 @@ ping_status_t ping_status:3; store_status_t store_status:3; swap_status_t swap_status:3; + Updatee *updatees; +#if USE_HINT_CACHE + hash_link hchash; +#endif }; struct _SwapDir { @@ -1623,6 +1659,7 @@ unsigned int accelerated:1; unsigned int internal:1; unsigned int body_sent:1; + unsigned int distify:1; /* Use dist reqs for consistency */ unsigned int reset_tcp:1; }; @@ -1672,6 +1709,8 @@ struct in_addr client_addr; struct in_addr my_addr; unsigned short my_port; + int dist_type; + unsigned short dist_port; HttpHeader header; ConnStateData *body_connection; /* used by clientReadBody() */ int content_length; @@ -1870,6 +1909,21 @@ int outs; int ins; } swap; + struct { + int dists; + int undists; + int updates; + kb_t update_kbytes; + int content_upd; + int updatees; + } dist; + struct { + int outs; + int ins; + kb_t kbytes_out; + kb_t kbytes_in; + int conflicts; + } put; }; /* per header statistics */ @@ -2159,10 +2213,149 @@ } flags; }; + + +/* + * Putting state. + */ +struct _PushHeader { + int fd; + store_client *sc; + struct { + unsigned int active:1; + unsigned int dead:1; + unsigned int disting:1; +#ifdef USE_ICP_DATA + unsigned int icpdata:1; +#endif + } flags; + int off; + int objlen; + StoreEntry *entry; + PF *handler; + void *arg; +#ifdef USE_ICP_DATA + icpQueue *q; +#endif + unsigned reqnum; /* ICP reqnum */ + char hname[20]; +}; + +struct _Pusher { + PushHeader hdr; + char data[16384 - sizeof(PushHeader)]; +}; + struct cache_dir_option { const char *name; void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring); void (*dump) (StoreEntry * e, const char *option, SwapDir * sd); }; + +/* Tracking state for update ("push") requester */ +struct _updatee { + struct _updatee *next; + StoreEntry *entry; /* Backpointer to relevant entry */ + struct sockaddr_in saddr; + time_t lastmod; + Pusher *p; +}; + + +#if USE_HINT_CACHE + +/* Hint Cache Interface */ +/* + * Primitive data types. All have a -Net format which has an + * agreed-upon endian-ness. + */ + + +struct _URLKeyNet { + HintCacheKey mungedKey; +}; + +struct _NodeKey { + dlink_node links; + HintCacheKey key; + struct sockaddr_in addr; +}; + +struct _HintCacheEntry { + URLKey key; + struct in_addr ipaddr; + unsigned short port; + short pad; /* Compiler padding space */ + unsigned int mtime; /* Last-modified time */ +}; + +/* This is what goes onto the net */ +struct _HintCacheEntryNet { + URLKeyNet mungedKey; + struct in_addr mungedIpaddr; + unsigned short mungedPort; + short mungedPad; + unsigned int mungedMtime; +}; + +struct _HintCacheUpdate { + unsigned char action; + char hopcount; + char UNUSED; /* Remove this field sometime XXX */ + char pad1; + int pad2; + HintCacheEntry entry; +}; + +struct _HintCacheUpdateNet { + unsigned char mungedAction; + char mungedHopcount; + char mungedUNUSED; + char mungedPad1; + int mungedPad2; + HintCacheEntryNet mungedEntry; +}; + +/* Hint Cache Disk */ +struct _HintCacheDiskEntry { + HintCacheEntry entry; + unsigned int rtime; /* Time of entry receipt */ +}; + +struct _HintCacheDisk { + unsigned int nbuckets; + int entriesPerBucket; + HintCacheDiskEntry *mmappedArray; + int fd; +}; + +typedef struct HintCacheNetS{ + StoreEntry *sendBuffer; + int sendLength; + enum HintCacheNet_State state; +#ifdef DOTEST + int testMode; + int testCount; +#endif +} HintCacheNet; + +typedef struct HintCacheNetHeaderS { + unsigned short httpport; /* Port of sending server */ + unsigned short updlen; /* Length of individual update */ +} HintCacheNetHeader; + +#endif /* USE_HINT_CACHE */ + +#if USE_ICP_DATA +typedef struct _icpDataStats { + int nsends; + int nrecvs; + int nfrags; + int ndups; + int ntmofrags; + int nbadfrags; +} +#endif + #endif /* SQUID_STRUCTS_H */ Index: squid/src/typedefs.h diff -u squid/src/typedefs.h:1.27 squid/src/typedefs.h:1.25.2.6 --- squid/src/typedefs.h:1.27 Sun Jun 23 06:38:04 2002 +++ squid/src/typedefs.h Tue Sep 3 10:42:00 2002 @@ -351,6 +351,37 @@ typedef int STDIRSELECT(const StoreEntry *); +/* PUT internal data structure */ +typedef struct _PushHeader PushHeader; +typedef struct _Pusher Pusher; + +/* Automatic update ("push") requester */ +typedef struct _updatee Updatee; + +#if USE_HINT_CACHE +/* Hint Cache Interface */ +typedef unsigned Net_unsigned; +typedef long long unsigned Net_longlong; +typedef unsigned long long HintCacheKey; +typedef struct _URLKey URLKey; +typedef struct _URLKeyNet URLKeyNet; +typedef struct _NodeKey NodeKey; +typedef struct _HintCacheEntry HintCacheEntry; +typedef struct _HintCacheEntryNet HintCacheEntryNet; +typedef struct _HintCacheUpdate HintCacheUpdate; +typedef struct _HintCacheUpdateNet HintCacheUpdateNet; + +/* Hint Cache Disk */ +typedef struct _HintCacheDiskEntry HintCacheDiskEntry; +typedef struct _HintCacheDisk HintCacheDisk; + +typedef dlink_node *HintCacheNodeListIter; +#endif /* USE_HINT_CACHE */ + +#if USE_ICP_DATA +typedef struct _icpDataStats icpDataStats; +#endif + typedef struct _external_acl external_acl; typedef struct _external_acl_entry external_acl_entry; Index: squid/src/url.c diff -u squid/src/url.c:1.10 squid/src/url.c:1.7.2.3 --- squid/src/url.c:1.10 Fri Aug 23 19:06:24 2002 +++ squid/src/url.c Tue Sep 3 10:42:01 2002 @@ -102,6 +102,9 @@ "whois", "internal", "https", +#if USE_HINT_CACHE + "route", +#endif "TOTAL" }; @@ -195,30 +198,84 @@ protocol_t -urlParseProtocol(const char *s) +urlParseProtocol(const char *s, u_short *dportp, int *dtypep) { + int proto; + /* test common stuff first */ - if (strcasecmp(s, "http") == 0) - return PROTO_HTTP; - if (strcasecmp(s, "ftp") == 0) - return PROTO_FTP; - if (strcasecmp(s, "https") == 0) - return PROTO_HTTPS; - if (strcasecmp(s, "file") == 0) - return PROTO_FTP; - if (strcasecmp(s, "gopher") == 0) - return PROTO_GOPHER; - if (strcasecmp(s, "wais") == 0) - return PROTO_WAIS; - if (strcasecmp(s, "cache_object") == 0) - return PROTO_CACHEOBJ; - if (strcasecmp(s, "urn") == 0) - return PROTO_URN; - if (strcasecmp(s, "whois") == 0) - return PROTO_WHOIS; - if (strcasecmp(s, "internal") == 0) - return PROTO_INTERNAL; - return PROTO_NONE; + if (strncasecmp(s, "http", 4) == 0) { + s += 4; + proto = PROTO_HTTP; + } +#if USE_HINT_CACHE + else if (strncasecmp(s, "route", 5) == 0) { + s += 5; + proto = PROTO_ROUTE; + } +#endif + else if (strncasecmp(s, "ftp", 3) == 0) { + s += 3; + proto = PROTO_FTP; + } + else if (strncasecmp(s, "https", 5) == 0) { + s += 5; + proto = PROTO_HTTPS; + } + else if (strncasecmp(s, "file", 4) == 0) { + s += 4; + proto = PROTO_FTP; + } + else if (strncasecmp(s, "gopher", 6) == 0) { + s += 6; + proto = PROTO_GOPHER; + } + else if (strncasecmp(s, "wais", 4) == 0) { + s += 4; + proto =PROTO_WAIS; + } + else if (strncasecmp(s, "cache_object", 12) == 0) { + s += 12; + proto = PROTO_CACHEOBJ; + } + else if (strncasecmp(s, "urn", 3) == 0) { + s += 3; + proto = PROTO_URN; + } + else if (strncasecmp(s, "whois", 5) == 0) { + s += 5; + proto = PROTO_WHOIS; + } + else if (strncasecmp(s, "internal", 8) == 0) { + s += 8; + proto = PROTO_INTERNAL; + } + else + proto = PROTO_NONE; + + if (dportp != NULL) { + if (strncasecmp(s, "dist", 4) == 0) { + s += 4; + if (dportp != NULL) + *dportp = ntohs(atoi(s)); + if (dtypep) + *dtypep = DIST_DIST; + } + else if (strncasecmp(s, "undist", 6) == 0) { + s += 6; + if (dportp != NULL) + *dportp = ntohs(atoi(s)); + if (dtypep) + *dtypep = DIST_UNDIST; + } + else { + if (dportp) + *dportp = 0; + if (dtypep) + *dtypep = 0; + } + } + + return proto; } @@ -256,7 +313,7 @@ request_t *request = NULL; char *t = NULL; char *q = NULL; - int port; + int port, dport, dtype; protocol_t protocol = PROTO_NONE; int l; proto[0] = host[0] = urlpath[0] = login[0] = '\0'; @@ -276,7 +333,7 @@ } else { if (sscanf(url, "%[^:]://%[^/]%[^\r\n]", proto, host, urlpath) < 2) return NULL; - protocol = urlParseProtocol(proto); + protocol = urlParseProtocol(proto, &dport, &dtype); port = urlDefaultPort(protocol); /* Is there any login informaiton? */ if ((t = strrchr(host, '@'))) { @@ -357,6 +414,8 @@ xstrncpy(request->host, host, SQUIDHOSTNAMELEN); xstrncpy(request->login, login, MAX_LOGIN_SZ); request->port = (u_short) port; + request->dist_port = (u_short) dport; + request->dist_type = dtype; return request; } Index: squid/src/webpush.c diff -u /dev/null squid/src/webpush.c:1.1.2.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/webpush.c Fri Dec 14 00:00:37 2001 @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUTBUFLEN 65536 +/*#define OUTBUFLEN 1400*/ + +char *malloc(); +void free(); +int atoi(); +int gethostname(); +int write(); + +void usage(); +int puthdr(struct stat *st); +void hfcopy(FILE *to, FILE *from, char *buf, int buflen, int hdrlen); + +char *verstr = "Server: Webpush 2.0, Squid PUT utility\r\n"; + +static int port = 3128; +static int verbose = 0; +static int directfile = 0; +static int async = 0; + +static char *cmdname; +static char name[256]; +static char reply[BUFSIZ]; +static char *url = 0; +static char *htfile = 0; +static char *type = "text/html"; +static char outbuf[OUTBUFLEN]; + +int main(argc, argv) +int argc; +char **argv; +{ + struct sockaddr_in addr; + int argcnt = 0; + struct stat st; + FILE *sp, *fp; + int hdrlen; + char *arg; + int code; + int s; + + cmdname = argv[0]; + if (argc < 3) + usage(); + while (--argc) { + arg = *++argv; + if (arg[0] == '-') { + while (*++arg) { + switch(*arg) { + case 'a': /* Asynchronous - don't wait for reply */ + async = 1; + break; + case 'h': /* Don't generate HTTP headers - already in file */ + directfile = 1; + break; + case 'p': /* Specify port */ + --argc; + if (argc < 1) + usage(); + port = atoi(*++argv); + if (port == 0) + usage(); + break; + case 't': /* Specify Content-type */ + --argc; + if (argc < 1) + usage(); + type = *++argv; + usage(); + break; + case 'v': /* Verbose */ + verbose = 1; + break; + default: + usage(); + } + } + } + else { + ++argcnt; + if (argcnt == 1) { + /* First non-flagged arg is the URL */ + url = arg; + } + else if (argcnt == 2) { + /* Second non-flagged arg is the file to push */ + htfile = arg; + } + else + usage(); + } + } + + if (argcnt != 2) + usage(); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == -1) { + perror("socket"); + exit(1); + } + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + addr.sin_port = htons(port); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { + perror("connect"); + exit(1); + } + sp = fdopen(s, "r+"); + if (sp == NULL) { + perror("socket fdopen"); + exit(1); + } + + fp = fopen(htfile, "r"); + if (fp == 0) { + perror(htfile); + exit(1); + } + + if (fstat(fileno(fp), &st) == -1) { + perror("fstat"); + exit(1); + } + + /* If directfile, then the file will already have HTTP headers */ + if (!directfile) { + /* Generate header and send to proxy */ + hdrlen = puthdr(&st); + if (verbose) { + fwrite(outbuf, 1, hdrlen, stdout); + } + } + + /* Copy file to proxy */ + if (verbose) + printf("sending file to proxy\n"); + hfcopy(sp, fp, outbuf, OUTBUFLEN, hdrlen); + + /* Read response */ + if (!async) { + if (verbose) + printf("proxy response is:\n"); + fread(reply, 1, sizeof(reply), sp); + reply[sizeof(reply) - 2] = '\n'; + reply[sizeof(reply) - 1] = '\0'; + + /* Parse response */ + sscanf(reply, "%s %d", name, &code); + + /* Print the complaint if the server seems unhappy */ + if ((code != 200 && code != 204) || verbose) + fputs(reply, stdout); + } + exit(0); +} + +void usage(err) +char *err; +{ + fprintf(stderr, "usage: %s [-h][-p port][-t content-type] \n", cmdname); + exit(1); +} + +/* Generate PUT header */ +int puthdr(statp) +struct stat *statp; +{ + struct tm *gmtime(); + char *asctime(); + char *timestr; + time_t now; + int hdrlen; + + now = time(0); + timestr = asctime(gmtime(&now)); + timestr[strlen(timestr) - 1] = '\0'; + + gethostname(name, sizeof(name)); + + if (url == 0) { + fprintf(stderr, "webpush internal problem - URL unknown\n"); + exit(1); + } + + hdrlen = 0; + sprintf(outbuf, "PUT %s HTTP/1.0\r\n", url); + hdrlen = strchr(outbuf, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Date: %s GMT\r\n", timestr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, verstr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Content-type: %s\r\n", type); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + sprintf(outbuf + hdrlen, "Content-length: %d\r\n", (int) statp->st_size); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 1; + + timestr = asctime(gmtime(&statp->st_mtime)); + timestr[strlen(timestr) - 1] = '\0'; + sprintf(outbuf + hdrlen, "Last-modified: %s GMT\r\n\r\n", timestr); + hdrlen = strchr(outbuf + hdrlen, '\n') - outbuf + 3; + + if (verbose) + printf("PUT header amounts to %d bytes\n", hdrlen); + + return(hdrlen); +} + +/* filecopy that makes allowances for an initial output header */ +void hfcopy(to, from, buf, buflen, hdrlen) +FILE *to, *from; +char *buf; +int buflen; +int hdrlen; +{ + int nmov, nwrote; + char *tbuf; + + while (1) { + nmov = fread(buf + hdrlen, 1, buflen - hdrlen, from); + if (nmov == -1) { + perror("filecopy read"); + exit(1); + } + if (nmov == 0) { + if (!feof(from)) + perror("webpost read"); + break; + } + nmov += hdrlen; + + tbuf = buf; + do { + if (verbose) + write(1, buf, nmov); + nwrote = write(fileno(to), buf, nmov); + if (nwrote == -1) { + perror("filecopy write"); + exit(1); + } + if (nwrote == 0) + break; + nmov -= nwrote; + tbuf += nwrote; + } while (nmov > 0); + + /* Sent header in first go-round, done now */ + hdrlen = 0; + } + if (verbose) + printf("filecopy complete - last move of %d chars\n", nmov); +} + Index: squid/src/auth/basic/helpers/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/Makefile.am:1.2.28.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/Makefile.am Tue Sep 3 10:42:05 2002 @@ -0,0 +1,7 @@ +# Makefile for storage modules in the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +DIST_SUBDIRS = getpwnam LDAP MSNT multi-domain-NTLM NCSA PAM SMB YP SASL +SUBDIRS = @BASIC_AUTH_HELPERS@ Index: squid/src/auth/basic/helpers/LDAP/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/LDAP/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/LDAP/Makefile.am Tue Sep 3 10:42:07 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid LDAP authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +libexec_PROGRAMS = squid_ldap_auth +man_MANS = squid_ldap_auth.8 +EXTRA_DIST = squid_ldap_auth.8 +squid_ldap_auth_SOURCES = squid_ldap_auth.c + +LDADD = -lldap -llber Index: squid/src/auth/basic/helpers/MSNT/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/MSNT/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/Makefile.am Tue Sep 3 10:42:10 2002 @@ -0,0 +1,22 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + + +libexec_PROGRAMS = msnt_auth + +msnt_auth_SOURCES = md4.c rfcnb-io.c rfcnb-util.c session.c msntauth.c \ + msntauth.h smbdes.c smbencrypt.c smblib-util.c smblib.c \ + valid.c denyusers.c allowusers.c confload.c \ + byteorder.h rfcnb-common.h rfcnb-error.h rfcnb.h \ + rfcnb-io.h rfcnb-priv.h rfcnb-util.h smblib-common.h \ + smblib.h smblib-priv.h std-defines.h std-includes.h valid.h + +LDADD = @XTRA_LIBS@ + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ Index: squid/src/auth/basic/helpers/MSNT/README.html diff -u /dev/null squid/src/auth/basic/helpers/MSNT/README.html:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/README.html Tue Sep 3 10:42:10 2002 @@ -0,0 +1,355 @@ + + + MSNTAUTH readme + + + + + ++MSNT Auth v2.0.3
+ +
+Squid web proxy NT authentication module
+Antonino Iannella, Stellar-X Pty Ltd
+Sun Sep 2 15:01:58 CST 2001 +Contents
+ ++
+ +- Introduction +
- Installation +
- Issues when compiling +
- Configuration file +
- Denying users +
- Allowing users +
- Squid.conf changes +
- Testing +
- Contact details +
- Reported problem +
- Revision history +
Introduction
+ ++This is an authentication module for the Squid proxy server +to authenticate users on an NT domain. + +
+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). + +
+Usage is simple. It accepts a username and password on standard input. +It 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. + +
+Msntauth is released under the GNU General Public License and +is available from +http://www.tripod.com/stellarx. +It also ships with the Squid web proxy, +http://www.squid-proxy.org. + +
+Msntauth has not been tested with Windows 2000 domains yet. + +
Installation
+ ++Make any changes to the source code you need. + +
+If you are using the source provided with Squid, then Msntauth +will be compiled when you compile Squid. Refer to Squid documentation +for details. + +
+If you have downloaded Msntauth from the Stellar-X website, then +copy
Makefile.MSNT
toMakefile
. +Review the Makefile, and modify based on target platform or +site requirements. + ++Type 'make', then 'make install', then 'make clean'. + +
+To avoid using the makefile, it may compile with + + gcc -O2 -s -o msntauth *.c + +
+'Make install' will put 'msntauth' into +/usr/local/squid/bin by default. + +
+Hopefully nobody has problems compiling msntauth. + +
Issues when compiling
+ ++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. +In Smbencrypt.c, '#include
' only gets included when +compiled with Solaris. + + +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. + +
+For Digital Unix/Tru64, review the INSTALL line in the makefile. + +
Configuration file
+ ++Msntauth uses a configuration file as of version 2. +The file is /usr/local/squid/etc/msntauth.conf. +If this path needs to be changed, it is defined in confload.c - + +
+ #define CONFIGFILE "/usr/local/squid/etc/msntauth.conf" ++ ++An example configuration file is provided. It looks like + +
+# 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 ++ ++All comments start with '#'. + +
+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.c. +At least one server must be specified, or msntauth will not +run. +Server names must be resolvable by the system. If not, msntauth +reports an error. If you can't ping it, you might have a host +resolution problem. +You can't use NetBIOS hostnames, nor IP addresses. + +
+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! + +
+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. + +
Denying users
+ ++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. + +
+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. + +
+Msntauth will send syslog messages if a user was denied, +at LOG_USER facility. + +
Allowing users
+ ++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. + +
+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. + +
+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. + +
+Some other rules - + +
+
+ +- The operation of the denied user file is independent of the +allowed user file. The former file is checked first. +
- You can use none, one, or both files. +
- If a username appears in the denied user file, they will +be denied, even if they are in the allowed user file. +
- If a username is not in either file, they will be denied, +because they have not been allowed. +
- If the allowed user file is in use and is empty, all +users will be allowed. +
+Hopefully this wasn't too confusing. + +
Squid.conf changes
+ ++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 - + +
+ acl+ +proxy_auth REQUIRED + http_access allow password + http_access allow + http_access deny all + +You will also need to review the following directives. The number of +msntauth children spawned is set with authenticate_children. +The number of children needed is site-dependent, so some +experimentation may be required to find the best number. +There should be no visible delay in performance with Squid once +msntauth is in use. As an example, a firm with 1500 users and a T1 +internet connection required a value of 30.- + +
+ proxy_auth_realm enterprise web gateway + authenticate_program /usr/local/squid/bin/msntauth + authenticate_ttl 5 + authenticate_children 20 ++ +Testing
+ ++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. + +
+It should behave in the following way - +
+ - 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. ++ ++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. + +
+Usernames cannot have whitespace in them, but passwords can. + +
+As of version 2.0.3, the msntauth version can be found in the executable. +Type this to retrieve it - + +
+ strings msntauth | grep -i msntauth ++ +Contact details
+ ++To contact the maintainer of this package, email Antonino Iannella +at antonino@rager.com.au, or antonino.iannella@santos.com.au, or ring ++61 8408 800 007. + +
+The latest version may be found on http://members.tripod.com/stellarx. +It is also distributed as part of Squid. + +
Reported problem
+ ++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. + +
+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 + +
+ patch smblib.c < smblib.c.patch ++ +Revision history
+ ++The following sequence 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. + +
+
+ +- Added many patches from Duane Wessels to stop compilation errors (?) +
- Improved the main() function yet again +
- Created a more informative Makefile +
- Added an 'allowed users' feature to complement the 'denied users' feature +
- Stopped the use of alarm() which was causing problems under Solaris +
- Added more syslog messages for authentication problems +
- Added the use of a configuration file, instead of hard-coding NT server details +
- Allowed for querying multiple NT servers and domains (this was a hot issue) +
- Changed README into an HTML document to improve readability +
- Removed denied/allowed username substring search limitation +
- Fixed a bug which occurred when reading denied/allowed usernames +
- Allows whitespace in passwords +
- To check user list changes, doesn't use an alarm every minute. +
- Fixed a sigaction compilation error, causing problems on FreeBSD and HPUX +
- Removed a problem of finding a valid username as a substring in the denied user list. +
- Support email address change from antonino@usa.net to antonino@rager.com.au. +
- Msntauth was successfully tested on Tru64. +
- PDC and BDC hostnames are now checked if they are resolvable. +
- Smbencrypt.c does not have to be checked for Solaris systems any more. +
- Imbedded version information in the executable. +
+Hopefully msntauth and Squid prove to be a valuable auditing combination. +Feel free to send me success or problem stories. + + + Index: squid/src/auth/basic/helpers/MSNT/allowusers.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/allowusers.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/allowusers.c Tue Sep 3 10:42:10 2002 @@ -0,0 +1,193 @@ + +/* + * 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
+#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 char CUBuf1[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 ", CUBuf1); + sprintf(CUBuf, " %s ", CUBuf1); + + 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, "Did not allow access to user '%s'.", CUBuf1); + 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(); + } +} Index: squid/src/auth/basic/helpers/MSNT/confload.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/confload.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/confload.c Tue Sep 3 10:42:11 2002 @@ -0,0 +1,249 @@ + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "msntauth.h" +#include "valid.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 */ + +static void ProcessLine(char *); +static void AddServer(char *, char *, char *); +static int QueryServerForUser(int, char *, char *); + +/* + * Opens and reads the configuration file. + * Returns 0 on success, or 1 for error. + */ + +int +OpenConfigFile(void) +{ + 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. */ + +static 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 server IP is resolvable. + * 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, "AddServer: Ignoring '%s' server line; too many servers.", ParamPDC); + return; + } + if (gethostbyname(ParamPDC) == (struct hostent *) NULL) { + syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamPDC); + return; + } + if (gethostbyname(ParamBDC) == (struct hostent *) NULL) { + syslog(LOG_USER | LOG_ERR, "AddServer: Ignoring host '%s'. Cannot resolve its address.", ParamBDC); + 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. + */ + +/* Define for systems which don't support it, like Solaris */ +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif + +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. + */ Index: squid/src/auth/basic/helpers/MSNT/denyusers.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/denyusers.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/denyusers.c Tue Sep 3 10:42:11 2002 @@ -0,0 +1,250 @@ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 char CUBuf1[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 ", CUBuf1); + sprintf(CUBuf, " %s ", CUBuf1); + + 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'.", CUBuf1); + 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; + } +} Index: squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm:1.2.62.1 --- /dev/null Mon Jan 26 04:57:39 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth-v2.0.lsm Tue Sep 3 10:42:11 2002 @@ -0,0 +1,13 @@ +Begin3 +Title: msntauth +Version: 2.0 +Entered-date: 01SEP01 +Description: Squid web proxy NT domain authentication module +Keywords: Squid WWW proxy SMB NT domain authentication module source +Author: antonino@rager.com.au (Antonino Iannella) +Maintained-by: antonino@rager.com.au (Antonino Iannella) +Primary-site: sunsite.unc.edu /pub/Linux/system/network/misc + msntauth-v2.0.tgz +Original-site: http://members.tripod.com/stellarx +Copying-policy: GPL +End Index: squid/src/auth/basic/helpers/MSNT/msntauth.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.c Tue Sep 3 10:42:12 2002 @@ -0,0 +1,112 @@ + +/* + * MSNT - Microsoft Windows NT domain squid authenticator module + * Version 2.0 by Stellar-X Pty Ltd, Antonino Iannella + * Sun Sep 2 14:39:53 CST 2001 + * + * 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 (wessels@squid-cache.org) + * + * 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 +#include +#include +#include + +#include "msntauth.h" + +extern char version[]; +char msntauth_version[] = "Msntauth v2.0.3 (C) 2 Sep 2001 Stellar-X Antonino Iannella."; + +/* 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. Read new ones. Use \n as a + * convenient EOL marker which is not even there. */ + username[0] = '\0'; + password[0] = '\0'; + sscanf(wstr, "%s %[^\n]", 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; +} Index: squid/src/auth/basic/helpers/MSNT/msntauth.conf diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.conf:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.conf Tue Sep 3 10:42:12 2002 @@ -0,0 +1,13 @@ + +# Sample MSNT authenticator configuration file +# Antonino Iannella, Stellar-X Pty Ltd +# Sun Sep 2 15:52:31 CST 2001 + +# NT hosts to use. Best to put their IP addresses in /etc/hosts. +server my_PDC my_BDC my_NTdomain +server other_PDC other_BDC otherdomain + +# Denied and allowed users. Comment these if not needed. +denyusers /usr/local/squid/etc/denyusers +allowusers /usr/local/squid/etc/allowusers + Index: squid/src/auth/basic/helpers/MSNT/msntauth.h diff -u /dev/null squid/src/auth/basic/helpers/MSNT/msntauth.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/msntauth.h Tue Sep 3 10:42:12 2002 @@ -0,0 +1,8 @@ +extern int OpenConfigFile(void); +extern int QueryServers(char *, char *); +extern void Checktimer(void); +extern void Check_forchange(); +extern int Read_denyusers(void); +extern int Read_allowusers(void); +extern int Check_user(char *); +extern int QueryServers(char *, char *); Index: squid/src/auth/basic/helpers/MSNT/rfcnb-io.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/rfcnb-io.c:1.3.2.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/rfcnb-io.c Tue Sep 3 10:42:13 2002 @@ -0,0 +1,419 @@ +/* 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 */ +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include +#include +#include + + +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 + /* AI - If you have problems with this line, contact the author */ + /* AI - This is the old line: inact.sa_mask = 0; */ + memset(&inact.sa_mask, 0, sizeof(inact.sa_mask)); +#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)); +} Index: squid/src/auth/basic/helpers/MSNT/smbencrypt.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smbencrypt.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smbencrypt.c Tue Sep 3 10:42:14 2002 @@ -0,0 +1,209 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* AI inclusion for Solaris filesystem */ +#ifdef SOLARIS +#include +#endif + +#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++; + } + } +} Index: squid/src/auth/basic/helpers/MSNT/smblib-util.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib-util.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smblib-util.c Tue Sep 3 10:42:15 2002 @@ -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 +#include +#include + +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)); + + } + } + +} Index: squid/src/auth/basic/helpers/MSNT/smblib.c diff -u /dev/null squid/src/auth/basic/helpers/MSNT/smblib.c:1.2.62.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/MSNT/smblib.c Tue Sep 3 10:42:15 2002 @@ -0,0 +1,554 @@ +/* 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 +#include +#include +#include +#include + +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); + +} Index: squid/src/auth/basic/helpers/PAM/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/PAM/Makefile.am:1.2.28.2 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/PAM/Makefile.am Tue Sep 3 10:42:17 2002 @@ -0,0 +1,15 @@ +# +# Makefile for the Squid PAM authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ + +man_MANS = pam_auth.8 +EXTRA_DIST = pam_auth.8 +libexec_PROGRAMS = pam_auth +LDADD = -lpam $(XTRA_LIBS) Index: squid/src/auth/basic/helpers/PAM/pam_auth.8 diff -u /dev/null squid/src/auth/basic/helpers/PAM/pam_auth.8:1.1.6.2 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/PAM/pam_auth.8 Tue Sep 3 10:42:17 2002 @@ -0,0 +1,94 @@ +.TH pam_auth 8 "15 May 2002" "Squid PAM Auth" +. +.SH NAME +pam_auth - Squid PAM authentication helper +. +.SH SYNOPSIS +squid_pam_auth [-n "service name"] [-t TTL] [-o] [-1] +. +.SH DESCRIPTION +This helper allows Squid to connect to a mostly any available PAM +database to validate the user name and password of Basic HTTP +authentication. +. +.TP +.BI "-s " "service-name" +Specifies the PAM service name Squid uses, defaults to "squid" +. +.TP +.BI "-t " TTL +Unless the -1 option is used, this specified for how long +the connection to the PAM database should be kept open and +reused for new logins. Defaults to 60 seconds. +. +.TP +.BI "-o" +Do not perform the PAM account management group (account +expiration etc) + +.TP +.BI "-1" +Specifies "One shot" mode, where a new PAM connection will +be opened for each new user. This is how PAM is normally +used and may be required by some backend databases. +The default is to reuse the PAM connection to maximize +performance. (see -t above) +. +.SH CONFIGURATION +. +The program needs a PAM service to be configured in +.B /etc/pam.conf +or +.B /etc/pam.d/ +.P +The default service name is "squid", and the program makes use +of the +.BR "" ' auth "' and '" account ' +management groups to verify the password and the accounts validity. +.P +For details on how to configure PAM services, see the PAM +documentation for your system. This manual does not cover PAM +configuration details. +. +.SH NOTES +. +When used for authenticating to local UNIX shadow password databases +the program must be running as root or else it won't have sufficient +permissions to access the user password database. Such use of this +program is not recommended, but if you absolutely need to then make +the program setuid root +.RS +.P +.B chown root pam_auth +.br +.B chmod u+s pam_auth +.RE +.P +Please note that in such configurations it is also strongly recommended +that the program is moved into a directory where normal users cannot +access it, as this mode of operation will allow any local user to +brute-force other users passwords. Also note the program has not been +fully audited and the author cannot be held responsible for any security +issues due to such installations. +. +.SH AUTHOR +Squid pam_auth and this manual is written by +.I Henrik Nordstrom +. +.SH COPYRIGHT +Squid pam_auth and this manual is Copyright 1999,2002 +Henrik Nordstrom +. +.SH QUESTIONS +Questions on the usage of this program can be sent to the +.I Squid Users +mailing list. +. +.SH REPORTING BUGS +Report bugs or bug-fixes to +.I Squid Bugs +or ideas for new improvements to +.I Squid Developers +. +.SH "SEE ALSO" +.BR pam (8), " PAM Systems Administrator Guide" Index: squid/src/auth/basic/helpers/SASL/.cvsignore diff -u /dev/null squid/src/auth/basic/helpers/SASL/.cvsignore:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/.cvsignore Tue Sep 3 10:42:17 2002 @@ -0,0 +1,2 @@ +.cvsignore +Makefile.in Index: squid/src/auth/basic/helpers/SASL/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/SASL/Makefile.am:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/Makefile.am Tue Sep 3 10:42:18 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid SASL authentication helper +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ + +libexec_PROGRAMS = sasl_auth +LDADD = -lsasl $(XTRA_LIBS) +EXTRA_DIST = squid_sasl_auth squid_sasl_auth.conf Index: squid/src/auth/basic/helpers/SASL/README diff -u /dev/null squid/src/auth/basic/helpers/SASL/README:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/README Tue Sep 3 10:42:18 2002 @@ -0,0 +1,49 @@ +This program authenticates users using SASL (specifically the +cyrus-sasl authentication method). + +SASL is configurable (somewhat like PAM). Each service authenticating +against SASL identifies itself with an application name. Each +"application" can be configured independently by the SASL administrator. + +For this authenticator, the SASL application name is, by default, + + squid_sasl_auth + +To configure the authentication method used the file "squid_sasl_auth.conf" +can be placed in the appropriate location, usually "/usr/lib/sasl". + +The authentication database is defined by the "pwcheck_method" parameter. +Only the "PLAIN" authentication mechanism is used. + +Examples: + +pwcheck_method:sasldb + use sasldb - the default if no conf file is installed. +pwcheck_method:pam + use PAM +pwcheck_method:passwd + use traditional /etc/passwd +pwcheck_method:shadow + use slightly less traditional /etc/shadow + +Others methods may be supported by your cyrus-sasl implementation - +consult your cyrus-sasl documentation for information. + +Typically the authentication database (/etc/sasldb, /etc/shadow, pam) +can not be accessed by a "normal" user. You should use setuid/setgid +and an appropriate user/group on the executable to allow the +authenticator to access the appropriate password database. If the +access to the database is not permitted then the authenticator +will typically fail with "-1, generic error". + + chown root.mail sasl_auth + chmod ug+s sasl_auth + +If the application name ("squid_sasl_auth") will also be used for the +pam service name if pwcheck_method:pam is chosen. And example pam +configuration file "squid_sasl_auth" is also included. + + +Ian Castle +ian.castle@coldcomfortfarm.net +March 2002 Index: squid/src/auth/basic/helpers/SASL/sasl_auth.c diff -u /dev/null squid/src/auth/basic/helpers/SASL/sasl_auth.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/sasl_auth.c Tue Sep 3 10:42:18 2002 @@ -0,0 +1,103 @@ +/* + * $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ + * + * SASL authenticator module for Squid. + * Copyright (C) 2002 Ian Castle + * + * 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 using cyrus-sasl + * + * Compile this program with: gcc -Wall -o sasl_auth sasl_auth.c -lsasl + * + */ +#include +#include +#include +#include +#include + +#define APP_NAME_SASL "squid_sasl_auth" + +int +main() +{ + char line[8192]; + char *username, *password; + const char *errstr; + + int rc; + sasl_conn_t *conn = NULL; + + /* make standard output line buffered */ + setvbuf(stdout, NULL, _IOLBF, 0); + + rc = sasl_server_init( NULL, APP_NAME_SASL ); + + if ( rc != SASL_OK ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + fprintf( stdout, "ERR\n" ); + return 1; + } + + rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn ); + + if ( rc != SASL_OK ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + fprintf( stdout, "ERR\n" ); + return 1; + } + + while ( fgets( line, sizeof( line ), stdin )) { + username = &line[0]; + password = strchr( line, '\n' ); + if ( !password) { + fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); + fprintf( stdout, "ERR\n" ); + continue; + } + *password = '\0'; + password = strchr ( line, ' ' ); + if ( !password) { + fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); + fprintf( stdout, "ERR\n" ); + continue; + } + *password++ = '\0'; + + rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr); + + if ( rc != SASL_OK ) { + if ( errstr ) { + fprintf( stderr, "errstr %s\n", errstr ); + } + if ( rc != SASL_BADAUTH ) { + fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); + } + fprintf( stdout, "ERR\n" ); + } + else { + fprintf( stdout, "OK\n" ); + } + + } + + sasl_dispose( &conn ); + sasl_done(); + + return 0; +} Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth Tue Sep 3 10:42:18 2002 @@ -0,0 +1,7 @@ +#%PAM-1.0 +# +# Example PAM service configuration file if using the sasl pam password +# backend (pwcheck_method:pam) +# +auth required /lib/security/pam_pwdb.so shadow nullok +account required /lib/security/pam_pwdb.so Index: squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf diff -u /dev/null squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/SASL/squid_sasl_auth.conf Tue Sep 3 10:42:18 2002 @@ -0,0 +1 @@ +pwcheck_method:sasldb Index: squid/src/auth/basic/helpers/winbind/Makefile.am diff -u /dev/null squid/src/auth/basic/helpers/winbind/Makefile.am:1.5.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/Makefile.am Tue Sep 3 10:42:22 2002 @@ -0,0 +1,11 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +libexec_PROGRAMS = wb_auth +wb_auth_SOURCES = wb_basic_auth.c wb_common.c +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src +LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth Index: squid/src/auth/basic/helpers/winbind/samba_nss.h diff -u /dev/null squid/src/auth/basic/helpers/winbind/samba_nss.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/samba_nss.h Tue Sep 3 10:42:22 2002 @@ -0,0 +1,105 @@ +#ifndef _NSSWITCH_NSS_H +#define _NSSWITCH_NSS_H +/* + Unix SMB/Netbios implementation. + Version 2.0 + + a common place to work out how to define NSS_STATUS on various + platforms + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_NSS_COMMON_H + +/* Sun Solaris */ + +#include +#include +#include + +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN + +#elif HAVE_NSS_H + +/* GNU */ + +#include + +typedef enum nss_status NSS_STATUS; + +#elif HAVE_NS_API_H + +/* SGI IRIX */ + +/* following required to prevent warnings of double definition + * of datum from ns_api.h +*/ +#ifdef DATUM +#define _DATUM_DEFINED +#endif + +#include + +typedef enum +{ + NSS_STATUS_SUCCESS=NS_SUCCESS, + NSS_STATUS_NOTFOUND=NS_NOTFOUND, + NSS_STATUS_UNAVAIL=NS_UNAVAIL, + NSS_STATUS_TRYAGAIN=NS_TRYAGAIN +} NSS_STATUS; + +#define NSD_MEM_STATIC 0 +#define NSD_MEM_VOLATILE 1 +#define NSD_MEM_DYNAMIC 2 + +#elif defined(HPUX) +/* HP-UX 11 */ + +#include "nsswitch/hp_nss_common.h" +#include "nsswitch/hp_nss_dbdefs.h" +#include + +#ifndef _HAVE_TYPEDEF_NSS_STATUS +#define _HAVE_TYPEDEF_NSS_STATUS +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN +#endif /* HPUX */ + +#else /* Nothing's defined. Neither gnu nor sun nor hp */ + +typedef enum +{ + NSS_STATUS_SUCCESS=0, + NSS_STATUS_NOTFOUND=1, + NSS_STATUS_UNAVAIL=2, + NSS_STATUS_TRYAGAIN=3 +} NSS_STATUS; + +#endif + +#endif /* _NSSWITCH_NSS_H */ Index: squid/src/auth/basic/helpers/winbind/wb_basic_auth.c diff -u /dev/null squid/src/auth/basic/helpers/winbind/wb_basic_auth.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/wb_basic_auth.c Tue Sep 3 10:42:22 2002 @@ -0,0 +1,121 @@ +/* + * (C) 2000 Francesco Chemolli + * + * 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 "wbntlm.h" +#include "util.h" +/* stdio.h is included in wbntlm.h */ +#include +#include +#include +#include /* for gettimeofday */ +#include /* BUG: is this portable? */ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" + +char debug_enabled=1; +char *myname; +pid_t mypid; + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response); + + +void do_authenticate(char *user, char *pass) { + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS winbindd_result; + + memset(&request,0,sizeof(struct winbindd_request)); + memset(&response,0,sizeof(struct winbindd_response)); + + + strncpy(request.data.auth.user,user,sizeof(fstring)-1); + strncpy(request.data.auth.pass,pass,sizeof(fstring)-1); + + winbindd_result = winbindd_request(WINBINDD_PAM_AUTH, + &request, &response); + debug("winbindd result: %d\n",winbindd_result); + + if (winbindd_result==WINBINDD_OK) { + SEND("OK"); + } else { + SEND("ERR"); + } + + return; /* useless */ +} + +void manage_request(void) { + char buf[BUFFER_SIZE+1]; + int length; + char *c, *user, *pass; + + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + warn("fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + + c=memchr(buf,'\n',BUFFER_SIZE); + if (c) { + *c='\0'; + length=c-buf; + } + else { + warn("No newline in '%s'. Dying.\n",buf); + exit(1); + } + + debug("Got '%s' from squid (length: %d).\n",buf,length); + user=buf; + + pass=memchr(buf,' ',length); + if (!pass) { + warn("Password not found. Denying access\n"); + SEND("ERR"); + return; + } + *pass='\0'; + pass++; + + do_authenticate(user,pass); + +} + +int main (int argc, char ** argv) { + if (argc > 0) { /* should always be true */ + myname=strrchr(argv[0],'/'); + if (myname==NULL) + myname=argv[0]; + } else { + myname="(unknown)"; + } + mypid=getpid(); + debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__ + " starting up...\n"); + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + while(1) { + manage_request(); + } + return 0; +} Index: squid/src/auth/basic/helpers/winbind/wb_common.c diff -u /dev/null squid/src/auth/basic/helpers/winbind/wb_common.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/wb_common.c Tue Sep 3 10:42:23 2002 @@ -0,0 +1,398 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + winbind client common code + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" +#include "config.h" + + +/* Global variables. These are effectively the client state information */ + +int winbindd_fd = -1; /* fd for winbindd socket */ +static char *excluded_domain; + +/* Free a response structure */ + +void free_response(struct winbindd_response *response) +{ + /* Free any allocated extra_data */ + + if (response) + SAFE_FREE(response->extra_data); +} + +/* + smbd needs to be able to exclude lookups for its own domain +*/ +void winbind_exclude_domain(const char *domain) +{ + SAFE_FREE(excluded_domain); + excluded_domain = strdup(domain); +} + + +/* Initialise a request structure */ + +void init_request(struct winbindd_request *request, int request_type) +{ + static char *domain_env; + static BOOL initialised; + + request->length = sizeof(struct winbindd_request); + + request->cmd = (enum winbindd_cmd)request_type; + request->pid = getpid(); + request->domain[0] = '\0'; + + if (!initialised) { + initialised = True; + domain_env = getenv(WINBINDD_DOMAIN_ENV); + } + + if (domain_env) { + strncpy(request->domain, domain_env, + sizeof(request->domain) - 1); + request->domain[sizeof(request->domain) - 1] = '\0'; + } +} + +/* Initialise a response structure */ + +void init_response(struct winbindd_response *response) +{ + /* Initialise return value */ + + response->result = WINBINDD_ERROR; +} + +/* Close established socket */ + +void close_sock(void) +{ + if (winbindd_fd != -1) { + close(winbindd_fd); + winbindd_fd = -1; + } +} + +/* Connect to winbindd socket */ + +int winbind_open_pipe_sock(void) +{ + struct sockaddr_un sunaddr; + static pid_t our_pid; + struct stat st; + pstring path; + + if (our_pid != getpid()) { + close_sock(); + our_pid = getpid(); + } + + if (winbindd_fd != -1) { + return winbindd_fd; + } + + /* Check permissions on unix socket directory */ + + if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) { + return -1; + } + + if (!S_ISDIR(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, "/", sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + ZERO_STRUCT(sunaddr); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1); + + /* If socket file doesn't exist, don't bother trying to connect + with retry. This is an attempt to make the system usable when + the winbindd daemon is not running. */ + + if (lstat(path, &st) == -1) { + return -1; + } + + /* Check permissions on unix socket file */ + + if (!S_ISSOCK(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + return -1; + } + + if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) == -1) { + close_sock(); + return -1; + } + + return winbindd_fd; +} + +/* Write data to winbindd socket with timeout */ + +int write_sock(void *buffer, int count) +{ + int result, nwritten; + + /* Open connection to winbind daemon */ + + restart: + + if (winbind_open_pipe_sock() == -1) { + return -1; + } + + /* Write data to socket */ + + nwritten = 0; + + while(nwritten < count) { + struct timeval tv; + fd_set r_fds; + + /* Catch pipe close on other end by checking if a read() + call would not block by calling select(). */ + + FD_ZERO(&r_fds); + FD_SET(winbindd_fd, &r_fds); + ZERO_STRUCT(tv); + + if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { + close_sock(); + return -1; /* Select error */ + } + + /* Write should be OK if fd not available for reading */ + + if (!FD_ISSET(winbindd_fd, &r_fds)) { + + /* Do the write */ + + result = write(winbindd_fd, + (char *)buffer + nwritten, + count - nwritten); + + if ((result == -1) || (result == 0)) { + + /* Write failed */ + + close_sock(); + return -1; + } + + nwritten += result; + + } else { + + /* Pipe has closed on remote end */ + + close_sock(); + goto restart; + } + } + + return nwritten; +} + +/* Read data from winbindd socket with timeout */ + +static int read_sock(void *buffer, int count) +{ + int result = 0, nread = 0; + + /* Read data from socket */ + + while(nread < count) { + + result = read(winbindd_fd, (char *)buffer + nread, + count - nread); + + if ((result == -1) || (result == 0)) { + + /* Read failed. I think the only useful thing we + can do here is just return -1 and fail since the + transaction has failed half way through. */ + + close_sock(); + return -1; + } + + nread += result; + } + + return result; +} + +/* Read reply */ + +int read_reply(struct winbindd_response *response) +{ + int result1, result2 = 0; + + if (!response) { + return -1; + } + + /* Read fixed length response */ + + if ((result1 = read_sock(response, sizeof(struct winbindd_response))) + == -1) { + + return -1; + } + + /* We actually send the pointer value of the extra_data field from + the server. This has no meaning in the client's address space + so we clear it out. */ + + response->extra_data = NULL; + + /* Read variable length response */ + + if (response->length > sizeof(struct winbindd_response)) { + int extra_data_len = response->length - + sizeof(struct winbindd_response); + + /* Mallocate memory for extra data */ + + if (!(response->extra_data = malloc(extra_data_len))) { + return -1; + } + + if ((result2 = read_sock(response->extra_data, extra_data_len)) + == -1) { + free_response(response); + return -1; + } + } + + /* Return total amount of data read */ + + return result1 + result2; +} + +/* + * send simple types of requests + */ + +NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request) +{ + struct winbindd_request lrequest; + + /* Check for our tricky environment variable */ + + if (getenv(WINBINDD_DONT_ENV)) { + return NSS_STATUS_NOTFOUND; + } + + /* smbd may have excluded this domain */ + if (excluded_domain && + strcasecmp(excluded_domain, request->domain) == 0) { + return NSS_STATUS_NOTFOUND; + } + + if (!request) { + ZERO_STRUCT(lrequest); + request = &lrequest; + } + + /* Fill in request and send down pipe */ + + init_request(request, req_type); + + if (write_sock(request, sizeof(*request)) == -1) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +/* + * Get results from winbindd request + */ + +NSS_STATUS winbindd_get_response(struct winbindd_response *response) +{ + struct winbindd_response lresponse; + + if (!response) { + ZERO_STRUCT(lresponse); + response = &lresponse; + } + + init_response(response); + + /* Wait for reply */ + if (read_reply(response) == -1) { + return NSS_STATUS_UNAVAIL; + } + + /* Throw away extra data if client didn't request it */ + if (response == &lresponse) { + free_response(response); + } + + /* Copy reply data from socket */ + if (response->result != WINBINDD_OK) { + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +/* Handle simple types of requests */ + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response) +{ + NSS_STATUS status; + + status = winbindd_send_request(req_type, request); + if (status != NSS_STATUS_SUCCESS) + return(status); + return winbindd_get_response(response); +} Index: squid/src/auth/basic/helpers/winbind/wbntlm.h diff -u /dev/null squid/src/auth/basic/helpers/winbind/wbntlm.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/wbntlm.h Tue Sep 3 10:42:23 2002 @@ -0,0 +1,90 @@ +/* + * (C) 2000 Francesco Chemolli , + * + * 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 _WBNTLM_H_ +#define _WBNTLM_H_ + +#include "config.h" +#include "ntlmauth.h" +#include +#include +#include +#include + + +/*************** CONFIGURATION ***************/ +#ifndef DEBUG +#define DEBUG +#endif + +/* the attempted entropy source. If it doesn't exist, random() is uesed */ +#define ENTROPY_SOURCE "/dev/urandom" + +#define DOMAIN "GCSINT" /* TODO: fix ntlm_make_challenge */ + +/************* END CONFIGURATION *************/ + +/* Debugging stuff */ +extern char *myname; +static char *__foo; +extern pid_t mypid; +extern char debug_enabled; + +#ifdef DEBUG +#define __DO_DEBUG 1 +#else +#define __DO_DEBUG 0 +#endif + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#define warn(X...) fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \ + ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\ + __LINE__);\ + fprintf(stderr,X) +#define debug(X...) if(__DO_DEBUG && debug_enabled) { warn(X); } +#else /* __GNUC__ */ +static void +debug(char *format,...) +{ +} +static void +warn(char *format,...) +{ +} +#endif /* __GNUC__ */ + + + +/* A couple of harmless helper macros */ +#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); +#ifdef __GNUC__ +#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); \ + printf(X "\n",Y) +#else +/* no gcc, no debugging. varargs macros are a gcc extension */ +#define SEND2 printf +#endif + +typedef enum { + YES, + NO, + DONTKNOW +} tristate; + +#define CHALLENGE_LEN 8 +#define BUFFER_SIZE 2010 + +#endif /* _WBNTLM_H_ */ Index: squid/src/auth/basic/helpers/winbind/winbind_nss_config.h diff -u /dev/null squid/src/auth/basic/helpers/winbind/winbind_nss_config.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/winbind_nss_config.h Tue Sep 3 10:42:23 2002 @@ -0,0 +1,148 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _WINBIND_NSS_CONFIG_H +#define _WINBIND_NSS_CONFIG_H + +/* Include header files from data in config.h file */ + +#include "config.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_UNIXSOCKET +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include +#include "samba_nss.h" + +/* Declarations for functions in winbind_nss.c + needed in winbind_nss_solaris.c (solaris wrapper to nss) */ + +NSS_STATUS _nss_winbind_setpwent(void); +NSS_STATUS _nss_winbind_endpwent(void); +NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result, + char* buffer, size_t buflen, int* errnop); + +NSS_STATUS _nss_winbind_setgrent(void); +NSS_STATUS _nss_winbind_endgrent(void); +NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getgrnam_r(const char *name, + struct group *result, char *buffer, + size_t buflen, int *errnop); +NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, + struct group *result, char *buffer, + size_t buflen, int *errnop); + +/* I'm trying really hard not to include anything from smb.h with the + result of some silly looking redeclaration of structures. */ + +#ifndef _PSTRING +#define _PSTRING +#define PSTRING_LEN 1024 +#define FSTRING_LEN 256 +typedef char pstring[PSTRING_LEN]; +typedef char fstring[FSTRING_LEN]; +#endif + +#ifndef _BOOL +#define _BOOL /* So we don't typedef BOOL again in vfs.h */ +#define False (0) +#define True (1) +#define Auto (2) +typedef int BOOL; +#endif + +#if !defined(uint32) +#if (SIZEOF_INT == 4) +#define uint32 unsigned int +#elif (SIZEOF_LONG == 4) +#define uint32 unsigned long +#elif (SIZEOF_SHORT == 4) +#define uint32 unsigned short +#endif +#endif + +#if !defined(uint16) +#if (SIZEOF_SHORT == 4) +#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16; +#else /* SIZEOF_SHORT != 4 */ +#define uint16 unsigned short +#endif /* SIZEOF_SHORT != 4 */ +#endif + +#ifndef uint8 +#define uint8 unsigned char +#endif + +/* zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/* zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } + +/* Some systems (SCO) treat UNIX domain sockets as FIFOs */ + +#ifndef S_IFSOCK +#define S_IFSOCK S_IFIFO +#endif + +#ifndef S_ISSOCK +#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK) +#endif + +#endif Index: squid/src/auth/basic/helpers/winbind/winbindd_nss.h diff -u /dev/null squid/src/auth/basic/helpers/winbind/winbindd_nss.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/basic/helpers/winbind/winbindd_nss.h Tue Sep 3 10:42:23 2002 @@ -0,0 +1,202 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef SAFE_FREE +#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0) +#endif + +#ifndef _WINBINDD_NTDOM_H +#define _WINBINDD_NTDOM_H + +#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */ +#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */ + +#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */ +#define WINBINDD_DONT_ENV "_NO_WINBINDD" + +/* Update this when you change the interface. */ + +#define WINBIND_INTERFACE_VERSION 2 + +/* Socket commands */ + +enum winbindd_cmd { + + WINBINDD_INTERFACE_VERSION, /* Always a well known value */ + + /* Get users and groups */ + + WINBINDD_GETPWNAM, + WINBINDD_GETPWUID, + WINBINDD_GETGRNAM, + WINBINDD_GETGRGID, + WINBINDD_GETGROUPS, + + /* Enumerate users and groups */ + + WINBINDD_SETPWENT, + WINBINDD_ENDPWENT, + WINBINDD_GETPWENT, + WINBINDD_SETGRENT, + WINBINDD_ENDGRENT, + WINBINDD_GETGRENT, + + /* PAM authenticate and password change */ + + WINBINDD_PAM_AUTH, + WINBINDD_PAM_AUTH_CRAP, + WINBINDD_PAM_CHAUTHTOK, + + /* List various things */ + + WINBINDD_LIST_USERS, /* List w/o rid->id mapping */ + WINBINDD_LIST_GROUPS, /* Ditto */ + WINBINDD_LIST_TRUSTDOM, + + /* SID conversion */ + + WINBINDD_LOOKUPSID, + WINBINDD_LOOKUPNAME, + + /* Lookup functions */ + + WINBINDD_SID_TO_UID, + WINBINDD_SID_TO_GID, + WINBINDD_UID_TO_SID, + WINBINDD_GID_TO_SID, + + /* Miscellaneous other stuff */ + + WINBINDD_CHECK_MACHACC, /* Check machine account pw works */ + WINBINDD_PING, /* Just tell me winbind is running */ + WINBINDD_INFO, /* Various bit of info. Currently just tidbits */ + + /* Placeholder for end of cmd list */ + + WINBINDD_NUM_CMDS +}; + +/* Winbind request structure */ + +struct winbindd_request { + uint32 length; + enum winbindd_cmd cmd; /* Winbindd command to execute */ + pid_t pid; /* pid of calling process */ + + union { + fstring username; /* getpwnam */ + fstring groupname; /* getgrnam */ + uid_t uid; /* getpwuid, uid_to_sid */ + gid_t gid; /* getgrgid, gid_to_sid */ + struct { + fstring user; + fstring pass; + } auth; /* pam_winbind auth module */ + struct { + unsigned char chal[8]; + fstring user; + fstring domain; + fstring lm_resp; + uint16 lm_resp_len; + fstring nt_resp; + uint16 nt_resp_len; + } auth_crap; + struct { + fstring user; + fstring oldpass; + fstring newpass; + } chauthtok; /* pam_winbind passwd module */ + fstring sid; /* lookupsid, sid_to_[ug]id */ + fstring name; /* lookupname */ + uint32 num_entries; /* getpwent, getgrent */ + } data; + fstring domain; /* {set,get,end}{pw,gr}ent() */ +}; + +/* Response values */ + +enum winbindd_result { + WINBINDD_ERROR, + WINBINDD_OK +}; + +/* Winbind response structure */ + +struct winbindd_response { + + /* Header information */ + + uint32 length; /* Length of response */ + enum winbindd_result result; /* Result code */ + + /* Fixed length return data */ + + union { + int interface_version; /* Try to ensure this is always in the same spot... */ + + /* getpwnam, getpwuid */ + + struct winbindd_pw { + fstring pw_name; + fstring pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + fstring pw_gecos; + fstring pw_dir; + fstring pw_shell; + } pw; + + /* getgrnam, getgrgid */ + + struct winbindd_gr { + fstring gr_name; + fstring gr_passwd; + gid_t gr_gid; + int num_gr_mem; + int gr_mem_ofs; /* offset to group membership */ + } gr; + + uint32 num_entries; /* getpwent, getgrent */ + struct winbindd_sid { + fstring sid; /* lookupname, [ug]id_to_sid */ + int type; + } sid; + struct winbindd_name { + fstring name; /* lookupsid */ + int type; + } name; + uid_t uid; /* sid_to_uid */ + gid_t gid; /* sid_to_gid */ + struct winbindd_info { + char winbind_separator; + fstring samba_version; + } info; + } data; + + /* Variable length return data */ + + void *extra_data; /* getgrnam, getgrgid, getgrent */ +}; + +#endif Index: squid/src/auth/ntlm/helpers/Makefile.am diff -u /dev/null squid/src/auth/ntlm/helpers/Makefile.am:1.2.28.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/Makefile.am Tue Sep 3 10:42:29 2002 @@ -0,0 +1,7 @@ +# Makefile for storage modules in the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +DIST_SUBDIRS = fakeauth no_check SMB winbind +SUBDIRS = @NTLM_AUTH_HELPERS@ Index: squid/src/auth/ntlm/helpers/SMB/Makefile.am diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/Makefile.am:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/Makefile.am Tue Sep 3 10:42:35 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +SUBDIRS = smbval + +libexec_PROGRAMS = ntlm_auth +ntlm_auth_SOURCES = libntlmssp.c ntlm_auth.c ntlm.h +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ -I$(srcdir)/smbval +LDADD = smbval/libsmbvalid.a -L$(top_builddir)/lib -lntlmauth \ + -lmiscutil $(CRYPTLIB) $(XTRA_LIBS) Index: squid/src/auth/ntlm/helpers/SMB/libntlmssp.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/libntlmssp.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/libntlmssp.c Tue Sep 3 10:42:36 2002 @@ -0,0 +1,286 @@ +/* + * (C) 2000 Francesco Chemolli + * 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. + */ + +typedef unsigned char uchar; + +#include "ntlm.h" +#include "util.h" /* from Squid */ +#include "valid.h" +#include "smbencrypt.h" + +#if HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#if HAVE_STDLIB_H +#include +#endif /* HAVE_STDLIB_H */ +#ifdef HAVE_UNISTD_H +#include +#endif + +/* these are part of rfcnb-priv.h and smblib-priv.h */ +extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len); +extern int SMB_Get_Last_Error(); +extern int RFCNB_Get_Last_Errno(); + +#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 */ + + +#define ENCODED_PASS_LEN 24 +static char challenge[NONCE_LEN]; +static char lmencoded_empty_pass[ENCODED_PASS_LEN], + ntencoded_empty_pass[ENCODED_PASS_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; +} + + +static char errstr[1001]; +/* returns 0 on success, > 0 on failure */ +static int +init_challenge(char *domain, char *domain_controller) +{ + int smberr; + + 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, 1000); + + + 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 security.\n"); + SMB_Discon(handle, 0); + handle = NULL; + return 3; + } + memcpy(challenge, handle->Encrypt_Key, NONCE_LEN); + SMBencrypt("",challenge,lmencoded_empty_pass); + SMBNTencrypt("",challenge,ntencoded_empty_pass); + return 0; +} + +static char my_domain[100], my_domain_controller[100]; +const char * +make_challenge(char *domain, char *domain_controller) +{ + /* trying to circumvent some strange problem wih pointers in SMBLib */ + /* Ugly as hell, but the lib is going to be dropped... */ + strcpy(my_domain,domain); + strcpy(my_domain_controller,domain_controller); + if (init_challenge(my_domain, my_domain_controller) > 0) { + return NULL; + } + return ntlm_make_challenge(my_domain, my_domain_controller, challenge, NONCE_LEN); +} + +#define min(A,B) (Adomain); + if (tmp.str == NULL) + return NULL; + memcpy(p, tmp.str, tmp.l); + p += tmp.l; + *p++ = '\\'; + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); + if (tmp.str == NULL) + return NULL; + *(p + tmp.l) = '\0'; + return credentials; +} + +/* 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 + */ +char * +ntlm_check_auth(ntlm_authenticate * auth, int auth_length) +{ + int rv; + char pass[25] /*, encrypted_pass[40] */; + 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; + } + +/* debug("fetching domain\n"); */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); + if (tmp.str == NULL || tmp.l == 0) { + 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 || tmp.l == 0) { + 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'; + + + /* Authenticating against the NT response doesn't seem to work... */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse); + if (tmp.str == NULL || tmp.l == 0) { + 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'; + +#if 1 + debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'" + "(length: %d)\n", + user,lmencoded_empty_pass,tmp.str,tmp.l); + if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) { + fprintf(stderr,"Empty LM password supplied for user %s\\%s. " + "No-auth\n",domain,user); + ntlm_errno=NTLM_LOGON_ERROR; + return NULL; + } + + tmp = ntlm_fetch_string ((char *) auth, auth_length, &auth->ntresponse); + if (tmp.str != NULL && tmp.l != 0) { + debug ("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'" + "(length: %d)\n", + user,ntencoded_empty_pass,tmp.str,tmp.l); + if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) { + fprintf(stderr,"Empty NT password supplied for user %s\\%s. " + "No-auth\n",domain,user); + ntlm_errno=NTLM_LOGON_ERROR; + return NULL; + } + } +#endif + + /* TODO: check against empty password!!!!! */ + + + + debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass); + + rv = SMB_Logon_Server(handle, user, pass, domain, 1); + debug("Login attempt had result %d\n", rv); + + if (rv != NTV_NO_ERROR) { /* failed */ + ntlm_errno = rv; + return NULL; + } + *(user - 1) = '\\'; /* hack. Performing, but ugly. */ + + debug("credentials: %s\n", credentials); + return credentials; +} Index: squid/src/auth/ntlm/helpers/SMB/ntlm.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/ntlm.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/ntlm.h Tue Sep 3 10:42:36 2002 @@ -0,0 +1,107 @@ +/* + * (C) 2000 Francesco Chemolli , + * inspired by previous work by Andrew 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 +#endif +#if HAVE_SYS_TIME_H +#include +#endif + +/************* CONFIGURATION ***************/ +/* + * define this if you want debugging + */ +#ifndef DEBUG +#define DEBUG +#endif + +#define DEAD_DC_RETRY_INTERVAL 30 + +/************* END CONFIGURATION ***************/ + +#include + + +/* Debugging stuff */ + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#ifdef DEBUG +#include +#include +static char *__foo; +extern char debug_enabled; +#define debug(X...) if (debug_enabled) { \ + 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__ */ +static void +debug(char *format,...) +{ +} + +#endif + + +/* A couple of harmless helper macros */ +#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); +#ifdef __GNUC__ +#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); +#else +/* no gcc, no debugging. varargs macros are a gcc extension */ +#define SEND2 printf +#endif + +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_UNTRUSTED_DOMAIN 4 +#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); +extern char *fetch_credentials(ntlm_authenticate * auth, int auth_length); +void dc_disconnect(void); +int connectedp(void); +int is_dc_ok(char *domain, char *domain_controller); + +typedef struct _dc dc; +struct _dc { + char *domain; + char *controller; + time_t dead; /* 0 if it's alive, otherwise time of death */ + dc *next; +}; + + +#endif /* _NTLM_H_ */ Index: squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/ntlm_auth.c Tue Sep 3 10:42:36 2002 @@ -0,0 +1,475 @@ +/* + * (C) 2000 Francesco Chemolli + * 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 "config.h" +#include "ntlmauth.h" +#include "ntlm.h" +#include "util.h" +#include "smbval/smblib-common.h" +#include "smbval/rfcnb-error.h" + +#include +#include + +/* these are part of rfcnb-priv.h and smblib-priv.h */ +extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len); +extern int SMB_Get_Last_Error(); +extern int SMB_Get_Last_SMB_Err(); +extern int RFCNB_Get_Last_Error(); + +#include + +#define BUFFER_SIZE 10240 + +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_GETOPT_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef DEBUG +char error_messages_buffer[BUFFER_SIZE]; +#endif + +char load_balance = 0, protocol_pedantic = 0; +#ifdef NTLM_FAIL_OPEN +char last_ditch_enabled = 0; +#endif + +dc *controllers = NULL; +int numcontrollers = 0; +dc *current_dc; + +char smb_error_buffer[1000]; + +/* signal handler to be invoked when the authentication operation + * times out */ +static char got_timeout = 0; +static void +timeout_during_auth(int signum) +{ + dc_disconnect(); +} + +/* 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++; + } +} + + +void +send_bh_or_ld(char *bhmessage, ntlm_authenticate * failedauth, int authlen) +{ +#ifdef NTLM_FAIL_OPEN + char *creds = NULL; + if (last_ditch_enabled) { + creds = fetch_credentials(failedauth, authlen); + if (creds) { + lc(creds); + SEND2("LD %s", creds); + } else { + SEND("NA last-ditch on, but no credentials"); + } + } else { +#endif + SEND2("BH %s", bhmessage); +#ifdef NTLM_FAIL_OPEN + } +#endif +} + +/* + * options: + * -b try load-balancing the domain-controllers + * -f fail-over to another DC if DC connection fails. + * DEPRECATED and VERBOSELY IGNORED. This is on by default now. + * -l last-ditch-mode + * domain\controller ... + */ +char *my_program_name = NULL; + +void +usage() +{ + fprintf(stderr, + "%s usage:\n%s [-b] [-f] [-d] domain\\controller [domain\\controller ...]\n-b, if specified, enables load-balancing among controllers\n-f, if specified, enables failover among controllers (DEPRECATED and always active)\n-l, if specified, changes behavior on domain controller failyures to\tlast-ditch.-d enables debugging statements if DEBUG was defined at build-time.\n\nYou MUST specify at least one Domain Controller.\nYou can use either \\ or / as separator between the domain name \n\tand the controller name\n", + my_program_name, my_program_name); +} + +char debug_enabled=0; + +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, "bfld"))) { + switch (opt) { + case 'b': + load_balance = 1; + break; + case 'f': + fprintf(stderr, + "WARNING. The -f flag is DEPRECATED and always active.\n"); + break; +#ifdef NTLM_FAIL_OPEN + case 'l': + last_ditch_enabled = 1; + break; +#endif + case 'd': + debug_enabled=1; + break; + default: + fprintf(stderr, "unknown option: -%c. Exiting\n", opt); + usage(); + 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 will not be freed in case of non-error. Since we don't reconfigure, + * it's going to live as long as the process anyways */ + d = malloc(strlen(argv[j]) + 1); + strcpy(d, argv[j]); + debug("Adding domain-controller %s\n", d); + if (NULL == (c = strchr(d, '\\')) && NULL == (c = strchr(d, '/'))) { + fprintf(stderr, "Couldn't grok domain-controller %s\n", d); + free(d); + continue; + } + /* more than one delimiter is not allowed */ + if (NULL != strchr(c + 1, '\\') || NULL != strchr(c + 1, '/')) { + fprintf(stderr, "Broken domain-controller %s\n", d); + free(d); + continue; + } + *c++ = '\0'; + new_dc = (dc *) malloc(sizeof(dc)); + if (!new_dc) { + fprintf(stderr, "Malloc error while parsing DC options\n"); + free(d); + continue; + } + /* capitalize */ + uc(c); + uc(d); + numcontrollers++; + new_dc->domain = d; + new_dc->controller = c; + new_dc->dead = 0; + 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"); + usage(); + 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 = NULL; + for (j = 0; j < numcontrollers; j++) { + debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n", + current_dc->domain, current_dc->controller, j + 1); + if (current_dc->dead != 0) { + if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) { + /* mark helper as retry-worthy if it's so. */ + debug("Reviving DC\n"); + current_dc->dead = 0; + } else { /* skip it */ + debug("Skipping it\n"); + continue; + } + } + /* else branch. Here we KNOW that the DC is fine */ + debug("attempting challenge retrieval\n"); + ch = make_challenge(current_dc->domain, current_dc->controller); + debug("make_challenge retuned %p\n", ch); + if (ch) { + debug("Got it\n"); + return ch; /* All went OK, returning */ + } + /* Huston, we've got a problem. Take this DC out of the loop */ + debug("Marking DC as DEAD\n"); + current_dc->dead = time(NULL); + /* Try with the next */ + debug("moving on to next controller\n"); + current_dc = current_dc->next; + } + /* all DCs failed. */ + return NULL; +} + + +void +manage_request() +{ + ntlmhdr *fast_header; + char buf[BUFFER_SIZE]; + const char *ch; + char *ch2, *decoded, *cred; + int plen; + + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + fprintf(stderr, "fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + debug("managing request\n"); + 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 */ + signal(SIGALRM, timeout_during_auth); + alarm(30); + cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen); + alarm(0); + signal(SIGALRM, SIG_DFL); + if (got_timeout != 0) { + fprintf(stderr, "ntlm-auth[%d]: Timeout during authentication.\n", getpid()); + SEND("BH Timeout during authentication"); + got_timeout = 0; + return; + } + if (cred == NULL) { + int smblib_err, smb_errorclass, smb_errorcode, nb_error; + if (ntlm_errno == NTLM_LOGON_ERROR) { /* hackish */ + SEND("NA Logon Failure"); + return; + } + /* there was an error. We have two errno's to look at. + * libntlmssp's erno is insufficient, we'll have to look at + * the actual SMB library error codes, to acually figure + * out what's happening. The thing has braindamaged interfacess..*/ + smblib_err = SMB_Get_Last_Error(); + smb_errorclass = SMBlib_Error_Class(SMB_Get_Last_SMB_Err()); + smb_errorcode = SMBlib_Error_Code(SMB_Get_Last_SMB_Err()); + nb_error = RFCNB_Get_Last_Error(); + debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n", + smblib_err, smb_errorclass, smb_errorcode, nb_error); + /* Should I use smblib_err? Actually it seems I can do as well + * without it.. */ + if (nb_error != 0) { /* netbios-level error */ + send_bh_or_ld("NetBios error!", + (ntlm_authenticate *) decoded, plen); + fprintf(stderr, "NetBios error code %d (%s)\n", nb_error, + RFCNB_Error_Strings[abs(nb_error)]); + return; + } + switch (smb_errorclass) { + case SMBC_SUCCESS: + debug("Huh? Got a SMB success code but could check auth.."); + SEND("NA Authentication failed"); + /* + * send_bh_or_ld("SMB success, but no creds. Internal error?", + * (ntlm_authenticate *) decoded, plen); + */ + return; + case SMBC_ERRDOS: + /*this is the most important one for errors */ + debug("DOS error\n"); + switch (smb_errorcode) { + /* two categories matter to us: those which could be + * server errors, and those which are auth errors */ + case SMBD_noaccess: /* 5 */ + SEND("NA Access denied"); + return; + case SMBD_badformat: + SEND("NA bad format in authentication packet"); + return; + case SMBD_badaccess: + SEND("NA Bad access request"); + return; + case SMBD_baddata: + SEND("NA Bad Data"); + return; + default: + send_bh_or_ld("DOS Error", + (ntlm_authenticate *) decoded, plen); + return; + } + case SMBC_ERRSRV: /* server errors */ + debug("Server error"); + switch (smb_errorcode) { + /* mostly same as above */ + case SMBV_badpw: + SEND("NA Bad password"); + return; + case SMBV_access: + SEND("NA Server access error"); + return; + default: + send_bh_or_ld("Server Error", + (ntlm_authenticate *) decoded, plen); + return; + } + case SMBC_ERRHRD: /* hardware errors don't really matter */ + send_bh_or_ld("Domain Controller Hardware error", + (ntlm_authenticate *) decoded, plen); + return; + case SMBC_ERRCMD: + send_bh_or_ld("Domain Controller Command Error", + (ntlm_authenticate *) decoded, plen); + 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(); + /* Robert says we can afford to wait forever. I'll trust him on this + * one */ + while (ch == NULL) { + sleep(30); + ch = obtain_challenge(); + } + SEND2("TT %s", ch); + return; + } + SEND("BH Helper detected protocol error"); + return; +/********* END ********/ + + +} + +int +main(int argc, char *argv[]) +{ + + debug("ntlm_auth build " __DATE__ ", " __TIME__ " starting up...\n"); +#ifdef DEBUG + debug("changing dir to /tmp\n"); + chdir("/tmp"); +#endif + + my_program_name = argv[0]; + 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) { + manage_request(); + } + return 0; +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/Makefile.am Tue Sep 3 10:42:37 2002 @@ -0,0 +1,13 @@ +# makefile for smblib + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ + +noinst_LIBRARIES = libsmbvalid.a +libsmbvalid_a_SOURCES = valid.c session.c rfcnb-util.c rfcnb-io.c \ + smblib-util.c smblib.c smbencrypt.c smbdes.c md4.c byteorder.h \ + rfcnb-error.h rfcnb-util.h smbencrypt.h smblib.h valid.h \ + md4.h rfcnb-io.h rfcnb.h smblib-common.h std-defines.h \ + rfcnb-common.h rfcnb-priv.h smbdes.h smblib-priv.h std-includes.h + +##OBJS = smblib.o smblib-util.o file.o smb-errors.o exper.o smblib-api.o smbencrypt.o smbdes.o md4.o Index: squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/byteorder.h Tue Sep 3 10:42:38 2002 @@ -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)) Index: squid/src/auth/ntlm/helpers/SMB/smbval/md4.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/md4.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/md4.c Tue Sep 3 10:42:38 2002 @@ -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 + */ +#include +#include "std-defines.h" /* for the types */ + +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; +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/md4.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/md4.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/md4.h Tue Sep 3 10:42:38 2002 @@ -0,0 +1 @@ +void mdfour(unsigned char *out, unsigned char *in, int n); Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-common.h Tue Sep 3 10:42:38 2002 @@ -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; Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-error.h Tue Sep 3 10:42:38 2002 @@ -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 ..." + * + * }; + */ Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.c Tue Sep 3 10:42:38 2002 @@ -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 */ +#include "config.h" +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include +#include +#include + +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)); +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-io.h Tue Sep 3 10:42:38 2002 @@ -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); Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-priv.h Tue Sep 3 10:42:39 2002 @@ -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__ */ Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.c Tue Sep 3 10:42:39 2002 @@ -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 +#include + +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include + + +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; + } +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb-util.h Tue Sep 3 10:42:39 2002 @@ -0,0 +1,52 @@ +/* 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. + */ + +#include "std-includes.h" + + +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); Index: squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/rfcnb.h Tue Sep 3 10:42:39 2002 @@ -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); Index: squid/src/auth/ntlm/helpers/SMB/smbval/session.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/session.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:40 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/session.c Tue Sep 3 10:42:40 2002 @@ -0,0 +1,389 @@ +/* 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 +#include +#include + +int RFCNB_errno = 0; +int RFCNB_saved_errno = 0; +#define RFCNB_ERRNO + +#include "std-includes.h" +#include +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" + +/* global data structures */ + +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; + +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.c Tue Sep 3 10:42:40 2002 @@ -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); +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smbdes.h Tue Sep 3 10:42:40 2002 @@ -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); Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.c Tue Sep 3 10:42:40 2002 @@ -0,0 +1,207 @@ +/* + * 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 "std-includes.h" +#include +#include +#include +#include +#include +#include + +#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++; + } + } +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smbencrypt.h Tue Sep 3 10:42:40 2002 @@ -0,0 +1,3 @@ +void SMBencrypt(uchar * passwd, uchar * c8, uchar * p24); +void SMBNTencrypt(uchar * passwd, uchar * c8, uchar * p24); + Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-common.h Tue Sep 3 10:42:41 2002 @@ -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__ */ Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-priv.h Tue Sep 3 10:42:41 2002 @@ -0,0 +1,651 @@ +#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 + +#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_ _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__ */ Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib-util.c Tue Sep 3 10:42:41 2002 @@ -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 +#include + +#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; +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib.c Tue Sep 3 10:42:42 2002 @@ -0,0 +1,575 @@ + +/* 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 +#include +#include + +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 + +/* #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, 1); /* Thanks Tridge! */ + 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); + +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/smblib.h Tue Sep 3 10:42:42 2002 @@ -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" Index: squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/std-defines.h Tue Sep 3 10:42:42 2002 @@ -0,0 +1,49 @@ +#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. + */ + +#include "squid_types.h" +#define BOOL int16_t +#define int16 int16_t +#define uint16 u_int16_t +#define int32 int32_t +#define uint32 u_int32_t + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#endif /* __STD_DEFINES__ */ Index: squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/std-includes.h Tue Sep 3 10:42:42 2002 @@ -0,0 +1,47 @@ +/* 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. + */ + +/* the types are provided by squid's configure preocess */ +#include "squid_types.h" +#define BOOL int16_t +#define int16 int16_t + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/* Pick up define for INADDR_NONE */ + +#ifndef INADDR_NONE +#define INADDR_NONE -1 +#endif Index: squid/src/auth/ntlm/helpers/SMB/smbval/valid.c diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/valid.c:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/valid.c Tue Sep 3 10:42:42 2002 @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#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); +} Index: squid/src/auth/ntlm/helpers/SMB/smbval/valid.h diff -u /dev/null squid/src/auth/ntlm/helpers/SMB/smbval/valid.h:1.2.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/SMB/smbval/valid.h Tue Sep 3 10:42:42 2002 @@ -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 Index: squid/src/auth/ntlm/helpers/winbind/Makefile.am diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/Makefile.am:1.5.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/winbind/Makefile.am Tue Sep 3 10:42:43 2002 @@ -0,0 +1,11 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-push-HEAD,v 1.1 2004/08/17 20:55:13 hno Exp $ +# + +libexec_PROGRAMS = wb_ntlmauth +wb_ntlmauth_SOURCES = wb_ntlm_auth.c wb_common.c +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src +LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth -lm Index: squid/src/auth/ntlm/helpers/winbind/samba_nss.h diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/samba_nss.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/winbind/samba_nss.h Tue Sep 3 10:42:43 2002 @@ -0,0 +1,105 @@ +#ifndef _NSSWITCH_NSS_H +#define _NSSWITCH_NSS_H +/* + Unix SMB/Netbios implementation. + Version 2.0 + + a common place to work out how to define NSS_STATUS on various + platforms + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_NSS_COMMON_H + +/* Sun Solaris */ + +#include +#include +#include + +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN + +#elif HAVE_NSS_H + +/* GNU */ + +#include + +typedef enum nss_status NSS_STATUS; + +#elif HAVE_NS_API_H + +/* SGI IRIX */ + +/* following required to prevent warnings of double definition + * of datum from ns_api.h +*/ +#ifdef DATUM +#define _DATUM_DEFINED +#endif + +#include + +typedef enum +{ + NSS_STATUS_SUCCESS=NS_SUCCESS, + NSS_STATUS_NOTFOUND=NS_NOTFOUND, + NSS_STATUS_UNAVAIL=NS_UNAVAIL, + NSS_STATUS_TRYAGAIN=NS_TRYAGAIN +} NSS_STATUS; + +#define NSD_MEM_STATIC 0 +#define NSD_MEM_VOLATILE 1 +#define NSD_MEM_DYNAMIC 2 + +#elif defined(HPUX) +/* HP-UX 11 */ + +#include "nsswitch/hp_nss_common.h" +#include "nsswitch/hp_nss_dbdefs.h" +#include + +#ifndef _HAVE_TYPEDEF_NSS_STATUS +#define _HAVE_TYPEDEF_NSS_STATUS +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN +#endif /* HPUX */ + +#else /* Nothing's defined. Neither gnu nor sun nor hp */ + +typedef enum +{ + NSS_STATUS_SUCCESS=0, + NSS_STATUS_NOTFOUND=1, + NSS_STATUS_UNAVAIL=2, + NSS_STATUS_TRYAGAIN=3 +} NSS_STATUS; + +#endif + +#endif /* _NSSWITCH_NSS_H */ Index: squid/src/auth/ntlm/helpers/winbind/wb_common.c diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wb_common.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/winbind/wb_common.c Tue Sep 3 10:42:44 2002 @@ -0,0 +1,403 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + winbind client common code + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" +#include "config.h" + + +/* Global variables. These are effectively the client state information */ + +int winbindd_fd = -1; /* fd for winbindd socket */ +static char *excluded_domain; + +/* Free a response structure */ + +void +free_response(struct winbindd_response *response) +{ + /* Free any allocated extra_data */ + + if (response) + SAFE_FREE(response->extra_data); +} + +/* + smbd needs to be able to exclude lookups for its own domain +*/ +void +winbind_exclude_domain(const char *domain) +{ + SAFE_FREE(excluded_domain); + excluded_domain = strdup(domain); +} + + +/* Initialise a request structure */ + +void +init_request(struct winbindd_request *request, int request_type) +{ + static char *domain_env; + static BOOL initialised; + + request->length = sizeof(struct winbindd_request); + + request->cmd = (enum winbindd_cmd) request_type; + request->pid = getpid(); + request->domain[0] = '\0'; + + if (!initialised) { + initialised = True; + domain_env = getenv(WINBINDD_DOMAIN_ENV); + } + + if (domain_env) { + strncpy(request->domain, domain_env, sizeof(request->domain) - 1); + request->domain[sizeof(request->domain) - 1] = '\0'; + } +} + +/* Initialise a response structure */ + +void +init_response(struct winbindd_response *response) +{ + /* Initialise return value */ + + response->result = WINBINDD_ERROR; +} + +/* Close established socket */ + +void +close_sock(void) +{ + if (winbindd_fd != -1) { + close(winbindd_fd); + winbindd_fd = -1; + } +} + +/* Connect to winbindd socket */ + +int +winbind_open_pipe_sock(void) +{ + struct sockaddr_un sunaddr; + static pid_t our_pid; + struct stat st; + pstring path; + + if (our_pid != getpid()) { + close_sock(); + our_pid = getpid(); + } + + if (winbindd_fd != -1) { + return winbindd_fd; + } + + /* Check permissions on unix socket directory */ + + if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) { + return -1; + } + + if (!S_ISDIR(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, "/", sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + ZERO_STRUCT(sunaddr); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1); + + /* If socket file doesn't exist, don't bother trying to connect + * with retry. This is an attempt to make the system usable when + * the winbindd daemon is not running. */ + + if (lstat(path, &st) == -1) { + return -1; + } + + /* Check permissions on unix socket file */ + + if (!S_ISSOCK(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + return -1; + } + + if (connect(winbindd_fd, (struct sockaddr *) &sunaddr, + sizeof(sunaddr)) == -1) { + close_sock(); + return -1; + } + + return winbindd_fd; +} + +/* Write data to winbindd socket with timeout */ + +int +write_sock(void *buffer, int count) +{ + int result, nwritten; + + /* Open connection to winbind daemon */ + + restart: + + if (winbind_open_pipe_sock() == -1) { + return -1; + } + + /* Write data to socket */ + + nwritten = 0; + + while (nwritten < count) { + struct timeval tv; + fd_set r_fds; + + /* Catch pipe close on other end by checking if a read() + * call would not block by calling select(). */ + + FD_ZERO(&r_fds); + FD_SET(winbindd_fd, &r_fds); + ZERO_STRUCT(tv); + + if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { + close_sock(); + return -1; /* Select error */ + } + + /* Write should be OK if fd not available for reading */ + + if (!FD_ISSET(winbindd_fd, &r_fds)) { + + /* Do the write */ + + result = write(winbindd_fd, + (char *) buffer + nwritten, count - nwritten); + + if ((result == -1) || (result == 0)) { + + /* Write failed */ + + close_sock(); + return -1; + } + + nwritten += result; + + } else { + + /* Pipe has closed on remote end */ + + close_sock(); + goto restart; + } + } + + return nwritten; +} + +/* Read data from winbindd socket with timeout */ + +static int +read_sock(void *buffer, int count) +{ + int result = 0, nread = 0; + + /* Read data from socket */ + + while (nread < count) { + + result = read(winbindd_fd, (char *) buffer + nread, count - nread); + + if ((result == -1) || (result == 0)) { + + /* Read failed. I think the only useful thing we + * can do here is just return -1 and fail since the + * transaction has failed half way through. */ + + close_sock(); + return -1; + } + + nread += result; + } + + return result; +} + +/* Read reply */ + +int +read_reply(struct winbindd_response *response) +{ + int result1, result2 = 0; + + if (!response) { + return -1; + } + + /* Read fixed length response */ + + if ((result1 = read_sock(response, sizeof(struct winbindd_response))) + == -1) { + + return -1; + } + + /* We actually send the pointer value of the extra_data field from + * the server. This has no meaning in the client's address space + * so we clear it out. */ + + response->extra_data = NULL; + + /* Read variable length response */ + + if (response->length > sizeof(struct winbindd_response)) { + int extra_data_len = response->length - + sizeof(struct winbindd_response); + + /* Mallocate memory for extra data */ + + if (!(response->extra_data = malloc(extra_data_len))) { + return -1; + } + + if ((result2 = read_sock(response->extra_data, extra_data_len)) + == -1) { + free_response(response); + return -1; + } + } + + /* Return total amount of data read */ + + return result1 + result2; +} + +/* + * send simple types of requests + */ + +NSS_STATUS +winbindd_send_request(int req_type, struct winbindd_request * request) +{ + struct winbindd_request lrequest; + + /* Check for our tricky environment variable */ + + if (getenv(WINBINDD_DONT_ENV)) { + return NSS_STATUS_NOTFOUND; + } + + /* smbd may have excluded this domain */ + if (excluded_domain && strcasecmp(excluded_domain, request->domain) == 0) { + return NSS_STATUS_NOTFOUND; + } + + if (!request) { + ZERO_STRUCT(lrequest); + request = &lrequest; + } + + /* Fill in request and send down pipe */ + + init_request(request, req_type); + + if (write_sock(request, sizeof(*request)) == -1) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +/* + * Get results from winbindd request + */ + +NSS_STATUS +winbindd_get_response(struct winbindd_response * response) +{ + struct winbindd_response lresponse; + + if (!response) { + ZERO_STRUCT(lresponse); + response = &lresponse; + } + + init_response(response); + + /* Wait for reply */ + if (read_reply(response) == -1) { + return NSS_STATUS_UNAVAIL; + } + + /* Throw away extra data if client didn't request it */ + if (response == &lresponse) { + free_response(response); + } + + /* Copy reply data from socket */ + if (response->result != WINBINDD_OK) { + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +/* Handle simple types of requests */ + +NSS_STATUS +winbindd_request(int req_type, + struct winbindd_request * request, struct winbindd_response * response) +{ + NSS_STATUS status; + + status = winbindd_send_request(req_type, request); + if (status != NSS_STATUS_SUCCESS) + return (status); + return winbindd_get_response(response); +} Index: squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c:1.3.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/winbind/wb_ntlm_auth.c Tue Sep 3 10:42:44 2002 @@ -0,0 +1,425 @@ +/* + * (C) 2000 Francesco Chemolli + * (C) 2002 Andrew Bartlett + * + * 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. + * + */ +/* + * TODO: + * -add handling of the -d flag + * -move all squid-helper-protocol-related operations to helper functions + * -remove the hard-coded target NT domain name + * + * - MAYBE move squid-helper-protocol-related opetations to an external + * library? + */ + + +#include "wbntlm.h" +#include "util.h" +/* stdio.h is included in wbntlm.h */ +#include +#include +#include +#include /* for gettimeofday */ +#include /* BUG: is this portable? */ + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#if HAVE_GETOPT_H +#include +#endif + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" + +#ifndef min +#define min(x,y) ((x)<(y)?(x):(y)) +#endif + +void +authfail(char *domain, char *user, char *reason) +{ + /* TODO: -move away from SEND-type gcc-isms + * -prepare for protocol extension as soon as rbcollins is ready + */ + SEND2("NA %s\\%s auth failure because: %s", domain, user, reason); +} + +void +authok(const char *domain, const char *user) +{ + SEND2("AF %s\\%s", domain, user); +} + +void +sendchallenge(const char *challenge) +{ + SEND2("TT %s", challenge); +} + +void +helperfail(const char *reason) +{ + SEND2("BH %s", reason); +} + +char debug_enabled = 0; +char *myname; +pid_t mypid; + +static void +lc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = tolower(c); + p++; + } +} + +static void +uc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = toupper(c); + p++; + } +} + + + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, struct winbindd_response *response); + + +static tristate have_urandom = DONTKNOW; +FILE *urandom_file = NULL; + +void +init_random() +{ + if (have_urandom == DONTKNOW) { + int result = 0; + struct stat st; + result = stat(ENTROPY_SOURCE, &st); + if (result != 0 || !(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { + debug("Entropy source " ENTROPY_SOURCE " is unavailable\n"); + have_urandom = NO; + } + if ((urandom_file = fopen(ENTROPY_SOURCE, "r")) == NULL) { + unsigned int seed; + struct timeval t; + warn("Can't open entropy source " ENTROPY_SOURCE "\n"); + have_urandom = NO; + gettimeofday(&t, NULL); + seed = squid_random() * getpid() * t.tv_sec * t.tv_usec; + squid_srandom(seed); + } else { + have_urandom = YES; + } + } +} + +static unsigned char challenge[CHALLENGE_LEN + 1]; +static char * +build_challenge(void) +{ + size_t gotchars; + unsigned char j; + switch (have_urandom) { + case YES: + if ((gotchars = fread(&challenge, CHALLENGE_LEN, 1, urandom_file)) == 0) { + /* couldn't get a challenge. Fall back to random() and friends. + * notice that even a single changed byte is good enough for us */ + have_urandom = NO; + return build_challenge(); + } + return challenge; + case NO: + if (!(squid_random() % 100)) { /* sometimes */ + init_random(); + } + for (j = 0; j < CHALLENGE_LEN; j++) + challenge[j] = (unsigned char) (squid_random() % 256); + return challenge; + default: + warn("Critical internal error. Somebody forgot to initialize " + "the random system. Exiting.\n"); + exit(1); + } +} + +lstring lmhash, nthash; +static char have_nthash = 0; /* simple flag. A tad dirty.. */ + +void +do_authenticate(ntlm_authenticate * auth, int auth_length) +{ + lstring tmp; + int tocopy; + NSS_STATUS winbindd_result; + struct winbindd_request request; + struct winbindd_response response; + char *domain, *user; + + memset(&request, 0, sizeof(struct winbindd_request)); + + memset(&response, 0, sizeof(struct winbindd_response)); + + /* domain */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); + if (tmp.str == NULL || tmp.l == 0) { /* no domain supplied */ + request.data.auth_crap.domain[0] = 0; + } else { + tocopy = min(tmp.l + 1, sizeof(fstring)); + xstrncpy(request.data.auth_crap.domain, tmp.str, tocopy); + } + + domain = request.data.auth_crap.domain; /* just a shortcut */ + + /* username */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); + if (tmp.str == NULL || tmp.l == 0) { + authfail(domain, "-", "No username in request"); + return; + } + + tocopy = min(sizeof(fstring), tmp.l + 1); + xstrncpy(request.data.auth_crap.user, tmp.str, tocopy); + user = request.data.auth_crap.user; + + /* now the LM hash */ + lmhash = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse); + switch (lmhash.l) { + case 0: + warn("No lm hash provided by user %s\\%s\n", domain, user); + request.data.auth_crap.lm_resp_len = 0; + break; + case 24: + memcpy(request.data.auth_crap.lm_resp, lmhash.str, 24); + request.data.auth_crap.lm_resp_len = 24; + break; + default: + authfail(domain, user, "Broken LM hash response"); + return; + } + + nthash = ntlm_fetch_string((char *) auth, auth_length, &auth->ntresponse); + switch (nthash.l) { + case 0: + debug("no nthash\n"); + request.data.auth_crap.nt_resp_len = 0; + break; + case 24: + memcpy(request.data.auth_crap.nt_resp, nthash.str, 24); + request.data.auth_crap.nt_resp_len = 24; + break; + default: + debug("nthash len = %d\n", nthash.l); + authfail(domain, user, "Broken NT hash response"); + return; + } + + debug("Checking user '%s\\%s' lmhash len =%d, have_nthash=%d, " + "nthash len=%d\n", domain, user, lmhash.l, have_nthash, nthash.l); + + memcpy(request.data.auth_crap.chal, challenge, CHALLENGE_LEN); + + winbindd_result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, + &request, &response); + debug("winbindd result: %d\n", winbindd_result); + + if (winbindd_result == WINBINDD_OK) { + lc(domain); + lc(user); + authok(domain, user); + } else { + char error_buf[200]; + snprintf(error_buf, sizeof(error_buf), "Authentication Failure (%s)", + response.data.auth.error_string); + authfail(domain, user, error_buf); + } + return; /* useless */ +} + +void +manage_request(char *target_domain) +{ + char buf[BUFFER_SIZE + 1]; + char *c, *decoded; + ntlmhdr *fast_header; + + + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + warn("fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + + c = memchr(buf, '\n', BUFFER_SIZE); + if (c) + *c = '\0'; + else { + warn("No newline in '%s'. Dying.\n", buf); + exit(1); + } + + debug("Got '%s' from squid.\n", buf); + if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ + sendchallenge(ntlm_make_challenge(target_domain, NULL, + build_challenge(), CHALLENGE_LEN)); + return; + } + if (strncmp(buf, "KK ", 3) != 0) { /* not an auth-request */ + helperfail("illegal request received"); + warn("Illegal request received: '%s'\n", buf); + return; + } + /* At this point I'm sure it's a KK */ + decoded = base64_decode(buf + 3); + if (!decoded) { /* decoding failure, return error */ + authfail("-", "-", "Auth-format error, base64-decoding error"); + return; + } + fast_header = (struct _ntlmhdr *) decoded; + + /* sanity-check: it IS a NTLMSSP packet, isn't it? */ + if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + authfail("-", "-", "Broken NTLM packet, missing NTLMSSP signature"); + return; + } + /* Understand what we got */ + switch (fast_header->type) { + case NTLM_NEGOTIATE: + authfail("-", "-", "Received neg-request while expecting auth packet"); + return; + case NTLM_CHALLENGE: + authfail("-", "-", "Received challenge. Refusing to abide"); + return; + case NTLM_AUTHENTICATE: + do_authenticate((ntlm_authenticate *) decoded, + (strlen(buf) - 3) * 3 / 4); + return; + default: + helperfail("Unknown authentication packet type"); + return; + } + /* notreached */ + return; +} + +static char * +get_winbind_domain(void) +{ + struct winbindd_response response; + char *domain; + + ZERO_STRUCT(response); + + /* Send off request */ + + if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) != + NSS_STATUS_SUCCESS) { + warn("could not obtain winbind domain name!\n"); + exit(1); + } + + domain = strdup(response.data.domain_name); + uc(domain); + + warn("target domain is %s\n", domain); + return domain; +} + +char * +process_options(int argc, char *argv[]) +{ + int opt; + char *target_domain = NULL; + + while (-1 != (opt = getopt(argc, argv, "d"))) { + switch (opt) { + case 'd': + debug_enabled = 1; + break; + default: + warn("Unknown option: -%c. Exiting\n", opt); + exit(1); + break; /* not reached */ + } + if (optind >= argc - 1) { + target_domain = argv[optind]; + warn("target domain is %s\n", target_domain); + } + } + return target_domain; +} + +void +check_winbindd() +{ + NSS_STATUS r; + struct winbindd_request request; + struct winbindd_response response; + r = winbindd_request(WINBINDD_INTERFACE_VERSION, &request, &response); + if (r != WINBINDD_OK) { + warn("Can't contact winbindd. Dying\n"); + exit(1); + } + if (response.data.interface_version != WINBIND_INTERFACE_VERSION) { + warn("Winbind protocol mismatch. Align squid and samba. Dying\n"); + exit(1); + } +} + +int +main(int argc, char **argv) +{ + char *target_domain; + if (argc > 0) { /* should always be true */ + myname = strrchr(argv[0], '/'); + if (myname == NULL) + myname = argv[0]; + else + myname++; + } else { + myname = "(unknown)"; + } + mypid = getpid(); + target_domain = process_options(argc, argv); + debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__ + " starting up...\n"); + + check_winbindd(); + + if (target_domain == NULL) { + target_domain = get_winbind_domain(); + } + + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + init_random(); + while (1) { + manage_request(target_domain); + } + return 0; +} Index: squid/src/auth/ntlm/helpers/winbind/wbntlm.h diff -u /dev/null squid/src/auth/ntlm/helpers/winbind/wbntlm.h:1.3.10.1 --- /dev/null Mon Jan 26 04:57:41 2004 +++ squid/src/auth/ntlm/helpers/winbind/wbntlm.h Tue Sep 3 10:42:44 2002 @@ -0,0 +1,88 @@ +/* + * (C) 2000 Francesco Chemolli , + * + * 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 _WBNTLM_H_ +#define _WBNTLM_H_ + +#include "config.h" +#include "ntlmauth.h" +#include +#include