Table of Contents for
Squid: The Definitive Guide

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Squid: The Definitive Guide by Duane Wessels Published by O'Reilly Media, Inc., 2004
  1. Cover
  2. Squid: The Definitive Guide
  3. Squid: The Definitive Guide
  4. Dedication
  5. Preface
  6. 1. Introduction
  7. 2. Getting Squid
  8. 3. Compiling and Installing
  9. 4. Configuration Guide for the Eager
  10. 5. Running Squid
  11. 6. All About Access Controls
  12. 7. Disk Cache Basics
  13. 8. Advanced Disk Cache Topics
  14. 9. Interception Caching
  15. 10. Talking to Other Squids
  16. 11. Redirectors
  17. 12. Authentication Helpers
  18. 13. Log Files
  19. 14. Monitoring Squid
  20. 15. Server Accelerator Mode
  21. 16. Debugging and Troubleshooting
  22. A. Config File Reference
  23. http_port
  24. https_port
  25. ssl_unclean_shutdown
  26. icp_port
  27. htcp_port
  28. mcast_groups
  29. udp_incoming_address
  30. udp_outgoing_address
  31. cache_peer
  32. cache_peer_domain
  33. neighbor_type_domain
  34. icp_query_timeout
  35. maximum_icp_query_timeout
  36. mcast_icp_query_timeout
  37. dead_peer_timeout
  38. hierarchy_stoplist
  39. no_cache
  40. cache_access_log
  41. cache_log
  42. cache_store_log
  43. cache_swap_log
  44. emulate_httpd_log
  45. log_ip_on_direct
  46. cache_dir
  47. cache_mem
  48. cache_swap_low
  49. cache_swap_high
  50. maximum_object_size
  51. minimum_object_size
  52. maximum_object_size_in_memory
  53. cache_replacement_policy
  54. memory_replacement_policy
  55. store_dir_select_algorithm
  56. mime_table
  57. ipcache_size
  58. ipcache_low
  59. ipcache_high
  60. fqdncache_size
  61. log_mime_hdrs
  62. useragent_log
  63. referer_log
  64. pid_filename
  65. debug_options
  66. log_fqdn
  67. client_netmask
  68. ftp_user
  69. ftp_list_width
  70. ftp_passive
  71. ftp_sanitycheck
  72. cache_dns_program
  73. dns_children
  74. dns_retransmit_interval
  75. dns_timeout
  76. dns_defnames
  77. dns_nameservers
  78. hosts_file
  79. diskd_program
  80. unlinkd_program
  81. pinger_program
  82. redirect_program
  83. redirect_children
  84. redirect_rewrites_host_header
  85. redirector_access
  86. redirector_bypass
  87. auth_param
  88. authenticate_ttl
  89. authenticate_cache_garbage_interval
  90. authenticate_ip_ttl
  91. external_acl_type
  92. wais_relay_host
  93. wais_relay_port
  94. request_header_max_size
  95. request_body_max_size
  96. refresh_pattern
  97. quick_abort_min
  98. quick_abort_max
  99. quick_abort_pct
  100. negative_ttl
  101. positive_dns_ttl
  102. negative_dns_ttl
  103. range_offset_limit
  104. connect_timeout
  105. peer_connect_timeout
  106. read_timeout
  107. request_timeout
  108. persistent_request_timeout
  109. client_lifetime
  110. half_closed_clients
  111. pconn_timeout
  112. ident_timeout
  113. shutdown_lifetime
  114. acl
  115. http_access
  116. http_reply_access
  117. icp_access
  118. miss_access
  119. cache_peer_access
  120. ident_lookup_access
  121. tcp_outgoing_tos
  122. tcp_outgoing_address
  123. reply_body_max_size
  124. cache_mgr
  125. cache_effective_user
  126. cache_effective_group
  127. visible_hostname
  128. unique_hostname
  129. hostname_aliases
  130. announce_period
  131. announce_host
  132. announce_file
  133. announce_port
  134. httpd_accel_host
  135. httpd_accel_port
  136. httpd_accel_single_host
  137. httpd_accel_with_proxy
  138. httpd_accel_uses_host_header
  139. dns_testnames
  140. logfile_rotate
  141. append_domain
  142. tcp_recv_bufsize
  143. err_html_text
  144. deny_info
  145. memory_pools
  146. memory_pools_limit
  147. forwarded_for
  148. log_icp_queries
  149. icp_hit_stale
  150. minimum_direct_hops
  151. minimum_direct_rtt
  152. cachemgr_passwd
  153. store_avg_object_size
  154. store_objects_per_bucket
  155. client_db
  156. netdb_low
  157. netdb_high
  158. netdb_ping_period
  159. query_icmp
  160. test_reachability
  161. buffered_logs
  162. reload_into_ims
  163. always_direct
  164. never_direct
  165. header_access
  166. header_replace
  167. icon_directory
  168. error_directory
  169. maximum_single_addr_tries
  170. snmp_port
  171. snmp_access
  172. snmp_incoming_address
  173. snmp_outgoing_address
  174. as_whois_server
  175. wccp_router
  176. wccp_version
  177. wccp_incoming_address
  178. wccp_outgoing_address
  179. delay_pools
  180. delay_class
  181. delay_access
  182. delay_parameters
  183. delay_initial_bucket_level
  184. incoming_icp_average
  185. incoming_http_average
  186. incoming_dns_average
  187. min_icp_poll_cnt
  188. min_dns_poll_cnt
  189. min_http_poll_cnt
  190. max_open_disk_fds
  191. offline_mode
  192. uri_whitespace
  193. broken_posts
  194. mcast_miss_addr
  195. mcast_miss_ttl
  196. mcast_miss_port
  197. mcast_miss_encode_key
  198. nonhierarchical_direct
  199. prefer_direct
  200. strip_query_terms
  201. coredump_dir
  202. ignore_unknown_nameservers
  203. digest_generation
  204. digest_bits_per_entry
  205. digest_rebuild_period
  206. digest_rewrite_period
  207. digest_swapout_chunk_size
  208. digest_rebuild_chunk_percentage
  209. chroot
  210. client_persistent_connections
  211. server_persistent_connections
  212. pipeline_prefetch
  213. extension_methods
  214. request_entities
  215. high_response_time_warning
  216. high_page_fault_warning
  217. high_memory_warning
  218. ie_refresh
  219. vary_ignore_expire
  220. sleep_after_fork
  221. B. The Memory Cache
  222. C. Delay Pools
  223. D. Filesystem Performance Benchmarks
  224. E. Squid on Windows
  225. F. Configuring Squid Clients
  226. About the Author
  227. Colophon
  228. Copyright

Chapter 12. Authentication Helpers

I originally talked about proxy authentication in Section 6.1.2.12. However, I only explained how to write access control rules that use proxy authentication. Here, I’ll show you how to select and configure the particular authentication helpers.

Recall that Squid supports three methods for gathering authentication credentials from users: Basic, Digest, and NTLM. These methods specify how Squid receives the username and password from a client. From a security standpoint, Basic authentication is extremely weak. Digest and NTLM are significantly stronger. For each method, Squid provides some authentication modules, or helper processes, which actually validate the credentials.

All of the authentication helpers that I mention here are included in the Squid source code distribution. You can compile them with ./configure options that match their directory names. For example:

% ls helpers/basic_auth
LDAP                    NCSA                    getpwnam
MSNT                    PAM                     multi-domain-NTLM
Makefile                SASL                    winbind
Makefile.am             SMB
Makefile.in             YP

% ./configure --enable-basic-auth-helpers=LDAP,NCSA ...

Helper programs are normally installed in the $prefix/libexec directory.

As with redirectors, Squid uses a pool of authentication helper processes. A request for authentication is sent to the first idle helper. When all authenticator processes are busy, Squid queues pending requests. If the queue becomes too large, Squid exits with a fatal error message. In most cases, Squid caches authentication results. This reduces the load on the helper processes and improves response time.

Configuring Squid

The auth_param directive controls every aspect of configuring Squid’s authentication helpers. The different methods (Basic, Digest, NTLM) have some things in common, and some unique parameters. The first argument following auth_param must be one of basic, digest, or ntlm. I’ll cover this directive in detail for each authentication scheme later in the chapter.

In addition to auth_param, Squid has two more directives that affect proxy authentication. You can use the max_user_ip ACL to prevent users from sharing their username and password with others. If Squid detects the same username coming from too many different IP addresses, the ACL is a match and you can deny the request. For example:

acl FOO max_user_ip 2
acl BAR proxy_auth REQUIRED
http_access deny FOO
http_access allow BAR

In this case, if a user submits requests from three or more different IP addresses, Squid denies the request. The authenticate_ip_ttl directive controls how long Squid remembers the source IP addresses for each user. A smaller TTL makes it easier for users with frequently changing IP addresses. You can use larger TTLs in an environment where users have the same IP address for long periods of time.

HTTP Basic Authentication

Basic authentication is the simplest and least secure that HTTP has to offer. It essentially transmits user passwords as cleartext, although they are encoded into printable characters. For example, if the user types her name as Fannie and her password as FuRpAnTsClUb, the user-agent first combines the two into a single string, with name and password separated by a colon:

Fannie:FuRpAnTsClUb

Then it encodes this string with base64 encoding, as defined in RFC 2045. It looks like this in the HTTP headers:

Authorization: Basic RmFubmllOkZ1UnBBblRzQ2xVYgo=

Anyone who happens to capture your users’ HTTP requests can easily get both the username and password:

% echo RmFubmllOkZ1UnBBblRzQ2xVYgo= | /usr/local/lib/python1.5/base64.py -d
Fannie:FuRpAnTsClUb

As required by the HTTP/1.1 RFC, Squid doesn’t forward “consumed” authorization credentials to other servers. In other words, if the credentials are for access to Squid, the Authorization header is removed from outgoing requests.[1]

You’ll notice that some of the Basic authenticators can be configured to check the system password file. Because Basic credentials aren’t encrypted, it is a bad idea to combine login passwords with cache access passwords. If you choose to use the getpwnam authenticator, make sure you fully understand the implications of having your users’ passwords transmitted in the clear across your network.

HTTP Basic authentication supports the following auth_param parameters:

  • auth_param basic program command

  • auth_param basic children number

  • auth_param basic realm string

  • auth_param basic credentialsttl time-specification

The program parameter specifies the command, including arguments, for the helper program. In most cases, this will be the pathname to one of the authentication helper programs that you compiled. By default, they live in /usr/local/squid/libexec.

The children parameter tells Squid how many helper processes to use. The default value is 5, which is a good starting point if you don’t know how many Squid needs to handle the load. If you specify too few, Squid warns you with messages in cache.log.

The realm parameter is the authentication realm string that the user-agent should present to the user when prompting for a username and password. You can use something simple, such as “access to the Squid caching proxy.”

The credentialsttl parameter specifies the amount of time that Squid internally caches authentication results. A larger value reduces the load on the external authenticator processes, but increases the amount of time until Squid detects changes to the authentication database. Note, this only affects positive results (i.e., successful validations). Negative results aren’t cached inside Squid. The default TTL value is two hours.

Here is a complete example:

auth_param basic program /usr/local/squid/libexec/pam_auth
auth_param basic children 10
auth_param basic realm My Awesome Squid Cache
auth_param basic credentialsttl 1 hour

acl KnownUsers proxy_auth REQUIRED
http_access allow KnownUsers

Next I will discuss the Basic authentication helper programs that come with Squid.

NCSA

./configure —enable-basic-auth-helpers=NCSA

The NCSA authentication helper is relatively popular due to its simplicity and history. It stores usernames and passwords in a single text file, similar to the Unix /etc/passwd file. This password file format was originally developed as a part of the NCSA HTTP server project.

You pass the path to the password file as the program’s single command-line argument in squid.conf:

auth_param basic program /usr/local/squid/libexec/ncsa_auth
    /usr/local/squid/etc/passwd

You can use the htpasswd program that comes with Apache to create and update the password file. Also, you can download it from http://www.squid-cache.org/htpasswd/. From that page, you can also download the chpasswd CGI script, which allows users to change their own passwords if necessary.

LDAP

./configure —enable-basic-auth-helpers=LDAP

The LDAP helper interfaces to a Lightweight Directory Access Protocol server. The OpenLDAP libraries and header files must be installed before you can compile the squid_ldap_auth helper. You can find OpenLDAP at http://www.openldap.org/.

The squid_ldap_auth program requires at least two arguments: the base distinguished name (DN) and the LDAP server hostname. For example:

auth_param basic program /usr/local/squid/libexec/squid_ldap_auth
   -b "ou=people,dc=example,dc=com"  ldap.example.com

The LDAP helper has a Unix manual page that describes all of its options and parameters. However, Squid’s manual pages aren’t normally installed when you run make install. You can read the manual page by locating it in the source tree and manually running nroff. For example:

% cd helpers/basic_auth/LDAP
% nroff -man squid_ldap_auth.8 | less

MSNT

./configure —enable-basic-auth-helpers=MSNT

The MSNT authenticator interfaces to a Microsoft NT domain database via the Server Message Block (SMB) protocol. It uses a small configuration file, named msntauth.conf, which must be placed in the $prefix/etc or —sysconfidr directory. You can specify up to five NT domain controllers in the configuration file. For example:

server pdc1_host bdc1_host my_nt_domain
server pdc2_host bdc2_host another_nt_domain

By default, the MSNT authenticator allows any user validated by the server. However, it also has the ability to allow or deny specific usernames. If you create an allowusers file, only the users listed there are allowed access to Squid. You might want to use this feature if you have a large number of users on the NT server, but only a small number who are allowed to use the cache. Alternatively, you can create a denyusers file. Any user listed in that file is automatically denied access, even before checking the allowusers file.

Alternatively, you can allow or deny specific usernames by placing them in the proxy_auth ACL as described in Section 6.1.2.12.

For additional documentation, see the README.html file in the helpers/basic_auth/MSNT directory.

Multi-domain-NTLM

./configure —enable-basic-auth-helpers=multi-domain-NTLM

The multi-domain-NTLM authenticator is similar to MSNT. Both send queries to a Windows NT domain database. Whereas MSNT queries up to five domain controllers, the multi-domain-NTLM authenticator requires users to insert the NT domain name before their username, like this:

               ntdomain\username

The multi-domain-NTLM helper program is a relatively short Perl script. It relies on the Authen::SMB package from CPAN (http://www.cpan.org). If you don’t hardcode the domain controller hostnames in the Perl script, it utilizes the nmblookup program from the Samba package (http://www.samba.org) to discover them automatically.

The Perl script is named smb_auth.pl. It might look like this in squid.conf:

auth_param basic program /usr/local/squid/libexec/smb_auth.pl

Documentation for multi-domain-NTLM is thin, but if you understand Perl, you should be able to figure it out by reading the code.

PAM

./configure —enable-basic-auth-helpers=PAM

In a sense, Pluggable Authentication Modules (PAM) are the glue between authentication methods (e.g., one-time passwords, kerberos, smart cards) and applications requiring authentication services (e.g., ssh, ftp, imap). Your system’s /etc/pam.conf file describes which methods to use for each application.

To use Squid’s PAM authentication helper, you need to add “squid” as a service in the /etc/pam.conf file and specify which PAM modules to use. For example, to use the Unix password file on FreeBSD, you might put this in pam.conf:

squid  auth  required  pam_unix.so  try_first_pass

Tip

To check the Unix password database, the pam_auth process must run as root. This is a security risk and you must manually make the executable setuid root. If pam_auth doesn’t run as root, and it is configured to check the Unix password database, every request for authentication fails.

The PAM authenticator is documented with a manual page that you can find in the helpers/basic_auth/PAM directory.

SASL

./configure —enable-basic-auth-helpers=SASL

The Simple Authentication and Security Layer (SASL) is an IETF proposed standard, documented in RFC 2222. It is a protocol for negotiating security parameters for connection-based protocols (e.g., FTP, SMTP, HTTP). However, the SASL authenticator is similar to the PAM authenticator. It interfaces with a third-party library to query a number of different authentication databases.

Specifically, Squid’s SASL authenticator requires the Cyrus SASL library developed by Carnegie Mellon University. You can find it at http://asg.web.cmu.edu/sasl/.

You can configure the SASL authenticator to check the traditional password file, the PAM system, or any of the other databases supported by CMU’s library. For further information, see the README file in the helpers/basic_auth/SASL directory.

SMB

./configure —enable-basic-auth-helpers=SMB

SMB is another authenticator for Microsoft Windows databases. The authenticator itself is a C program. That program executes a shell script each time it talks to the Windows domain controller. The shell script contains commands from the Samba package. Thus, you’ll need to install Samba before using the SMB authenticator.

The SMB authenticator program, smb_auth takes the Windows domain name as an argument. For example:

auth_param basic program /usr/local/squid/libexec/smb_auth -W MYNTDOMAIN

You can list multiple domains by repeating the -W option. For full documentation, see http://www.hacom.nl/~richard/software/smb_auth.html.

YP

./configure —enable-basic-auth-helpers=YP

The YP authenticator checks a system’s “Yellow Pages” (a.k.a. NIS) directory. To use it with Squid, you need to provide the NIS domain name and the name of the password database, usually passwd.byname on the authenticator command line:

auth_param basic program /usr/local/squid/libexec/yp_auth my.nis.domain passwd.byname

The yp_auth program is relatively simple, but doesn’t have any documentation.

getpwnam

./configure —enable-basic-auth-helpers=getpwnam

This authenticator is simply an interface to the getpwnam() function found in the C library on Unix systems. The getpwnam() function looks in the system password file for a given username. If you use YP/NIS, getpwnam() checks those databases as well. On some operating systems, it may also utilize the PAM system. You can use this authenticator if your cache users have login accounts on the system where Squid is running. Alternatively, you could set up “nologin” accounts in the password file for your cache users.

winbind

./configure —enable-basic-auth-helpers=winbind

Winbind is a feature of the Samba suite of software. It allows Unix systems to utilize Windows NT user account information. The winbind authenticator is a client for the Samba winbindd daemon. You must have Samba installed and the winbindd daemon running before you can use this authenticator.

The name of the winbind Basic authenticator is wb_basic_auth. It typically looks like this in squid.conf:

auth_param basic program /usr/local/squid/libexec/wb_basic_auth

The Basic Auth API

The interface between Squid and a Basic authenticator is quite simple. Squid sends usernames and passwords to the authenticator process, separated by a space and terminated by a newline. The authenticator reads the username and password pairs on stdin. After checking the credentials, the authenticator writes either OK or ERR to stdout.

Tip

Any “URL-unsafe” characters are encoded according to the RFC 1738 rules. Thus, the name “jack+jill” becomes “jack%2bjill”. Squid accepts usernames and passwords that contain whitespace characters. For example “a password” becomes “a%20password”. The authenticator program should be prepared to handle whitespace and other special characters after decoding the name and password.

You can easily test a Basic authenticator on the command line. Simply run the authenticator program in a terminal window and enter usernames and passwords. Or, you can do it like this:

% echo "bueller pencil" | ./ncsa_auth /tmp/passwd
OK

Here is a simple template authenticator written in Perl:

#!/usr/bin/perl -wl

use URI::Escape;

$|=1;                   # don't buffer stdout
while (<>) {
    ($u,$p) = split;
    $u = uri_unescape($u);
    $p = uri_unescape($p);
    if (&valid($u,$p)) {
        print "OK";
    } else {
        print "ERR";
    }
}

sub valid {
    my $user = shift;
    my $pass = shift;
    ...
}

HTTP Digest Authentication

Digest authentication is designed to be significantly more secure than Basic. It makes extensive use of cryptographic hash functions and other tricks. Essentially, instead of sending a cleartext password, the user-agent sends a “message digest” of the password, username, and other information. (See RFC 2617 and O’Reilly’s HTTP: The Definitive Guide for more information.)

HTTP Digest authentication supports the following auth_param parameters:

  • auth_param digest program command

  • auth_param digest children number

  • auth_param digest realm string

  • auth_param digest nonce_garbage_interval time-specification

  • auth_param digest nonce_max_duration time-specification

  • auth_param digest nonce_max_count number

  • auth_param digest nonce_strictness on|off

The program, children, and realm parameters are the same as for Basic authentication. All of the unique parameters relate to Digest authentication’s use of something called nonce.

A nonce is a special string of data, which changes occasionally. During the authentication process, the server (Squid in this case) provides a nonce value to the client. The client uses the nonce value when generating the digest. Without the nonce data, an attacker could simply intercept and replay the digest values to gain access to Squid.

The nonce_garbage_interval parameter tells Squid how often to clean up the nonce cache. The default value is every 5 minutes. A very busy cache with many Digest authentication clients may benefit from more frequent nonce garbage collection.

The nonce_max_duration parameter specifies how long each nonce value remains valid. When a client attempts to use a nonce value older than the specified time, Squid generates a 401 (Unauthorized) response and sends along a fresh nonce value so the client can re-authenticate. The default value is 30 minutes. Note that any captured Authorization headers can be used in a replay attack until the nonce value expires. Setting the nonce_max_duration too low, however, causes Squid to generate 401 responses more often. Each 401 response essentially wastes the user’s time as the client and server renegotiate their authentication credentials.

The nonce_max_count parameter places an upper limit on how many times a nonce value may be used. After the specified number of requests, Squid returns a 401 (Unauthorized) response and a new nonce value. The default is 50 requests.

Nonce counts are another feature designed to prevent replay attacks. Squid sends qop=auth in its 401 responses. This causes user-agents to include a nonce count in their requests, and to use the nonce count when generating the digest itself. Nonce count values must always increase over time. A decreasing nonce count indicates a replay attack. However, the counts may increase, but skip some values, for example: 5,6,8,9. The nonce_strictness parameter determines what Squid does in this case. If set to on, Squid returns a 401 response if a nonce count doesn’t equal the previous nonce count plus one. If set to off, Squid allows gaps in the nonce count values.

Here is a complete example:

auth_param digest program /usr/local/squid/libexec/digest_pw
auth_param digest children 8
auth_param digest realm Access to Squid
auth_param digest nonce_garbage_interval 10 minutes
auth_param digest nonce_max_duration 45 minutes
auth_param digest nonce_max_count 100
auth_param digest nonce_strictness on

acl KnownUsers proxy_auth REQUIRED
http_access allow KnownUsers

Next I will discuss the Digest authentication helper programs that come with Squid.

password

./configure —enable-auth=digest —enable-digest-auth-helpers=password

This is a simple, reference implementation of Digest authentication for Squid. It demonstrates how to write a Digest-based authentication helper. This code simply reads usernames and passwords from a plaintext file. The format of this file is as follows:

username:password

The password file pathname is the single argument to the digest_pw_auth program. For example:

auth_param digest program /usr/local/squid/libexec/digest_pw_auth
        /usr/local/squid/etc/digest_passwd
auth_param digest realm Some Nifty Realm

Squid doesn’t provide any tools to maintain a password file in this format. If you choose to use Digest authentication, you must manage the file on your own, perhaps with a text editor or Perl scripts.

Digest Authentication API

If you’d like to write your own Digest authentication helper, you need to understand the communication between Squid and the helper process. The exchange is similar to that for Basic authentication, albeit a little more complicated.

The first difference is that Squid writes the username and realm string, rather than username and password, to the helper process. These strings are quoted and separated by a colon. For example:

"bobby":"Tom Landry Middle School"

The second difference is that the helper process returns an MD5 digest string, rather than OK, if the username is valid. As with Basic authentication, the helper process writes ERR if the user doesn’t exist or if the input from Squid is unparseable for some reason.

The helper returns an MD5 digest with the username, realm, and password. The three strings are concatenated together and separated by colons:

username:realm:password

Remember that the password isn’t sent in the HTTP request. Rather, the helper retrieves the user’s password from a database (like the plaintext file used by the password helper). For example, let’s say that Bobby’s password is CapeRs. The helper process receives the username and realm from Squid, gets the password from its database, and calculates an MD5 checksum of this string:

bobby:Tom Landry Middle School:CapeRs

The Squid source code includes a library function, DigestCalcHA1(), which implements this calculation. We can test all this in a terminal window to see what the helper returns:

% echo 'bobby:CapeRs' > /tmp/pw
% echo bogus_input | digest_pw_auth /tmp/pw
ERR
% echo "nouser":"some realm" | digest_pw_auth /tmp/pw
ERR
% echo '"bobby":"Tom Landry Middle School"' | digest_pw_auth /tmp/pw
c7ca3efda238c65b2d48684a51baa90e

Squid stores this MD5 checksum and uses it in other parts of the Digest authentication algorithm. Note that the checksum only changes when the user changes his password. In Squid’s current Digest implementation, these checksums are kept in memory as long as the user remains active. If the user is inactive for authenticate_ttl seconds, the MD5 checksum may be removed from Squid’s memory. Upon the next request from that user, Squid asks the external helper process to calculate it again.

Microsoft NTLM Authentication

NTLM[2] is a proprietary connection authentication protocol from Microsoft. A number of groups, including the Squid developers, have reverse-engineered the protocol from what little information is available and by examining network traffic. You can find some technical details at http://www.innovation.ch/java/ntlm.html.

NTLM uses a three-way handshake to authenticate a connection. First, the client sends its request with a couple of identifiers. Second, the server sends back a challenge message. Third, the client sends its request again with a response to the challenge. At this point, the connection is authenticated and any further requests on the same connection don’t require any challenge/response information. If the connection is closed, the client and server must repeat the entire three-way handshake. Persistent connections help reduce this overhead for NTLM.

NTLM uses cryptographic hash functions and nonce values, similar to Digest authentication, although experts believe NTLM is weaker.

NTLM authentication supports the following auth_param parameters:

  • auth_param ntlm program command

  • auth_param ntlm children number

  • auth_param ntlm max_challenge_reuses number

  • auth_param ntlm max_challenge_lifetime time-specification

The program and children parameters are the same as for Basic and Digest authentication. The remaining parameters determine how often Squid may reuse a single challenge token.

The max_challenge_reuses parameter specifies how many times a challenge token may be reused. The default value is 0, so that challenges are never reused. Increasing this value may reduce the computational load on Squid and the NTLM helper processes, at the risk of weakening the protocol’s security.

Similarly, the max_challenge_lifetime parameter places a time limit on challenge reuses, even if the max_challenge_reuses count has not been reached. The default value is 60 seconds.

Here is a complete example:

auth_param ntlm program /usr/local/squid/libexec/ntlm_auth foo\bar
auth_param ntlm children 12
auth_param ntlm max_challenge_reuses 5
auth_param ntlm max_challenge_lifetime 2 minutes

acl KnownUsers proxy_auth REQUIRED
http_access allow KnownUsers

Squid comes with the following NTLM authentication helper programs:

SMB

./configure —enable-auth=ntlm —enable-ntlm-auth-helpers=SMB

The Server Message Block (SMB) authenticator for NTLM is similar to those for Basic authentication. Your users can simply supply their Windows NT domain, username, and password. This authenticator can load balance between multiple domain controllers. The domain and controller names go on the command line:

auth_param ntlm program /usr/local/squid/libexec/ntlm_auth
    domain\controller [domain\controller ...]

winbind

./configure —enable-auth=ntlm —enable-ntlm-auth-helpers=winbind

This authenticator is similar to winbind for Basic authentication. Both require that you have the Samba winbindd daemon installed and running. The name of the winbind Basic authenticator is wb_nltm_auth. It typically looks like this in squid.conf:

auth_param basic program /usr/local/squid/libexec/wb_ntlm_auth

NTLM Authentication API

The communication between Squid and an NTLM authenticator is much more complicated than for Basic and Digest. One reason is that each helper process actually creates its own challenge. Thus, helpers become “stateful” and Squid must remember which connections belong to which helpers.

Squid and the helper processes use a handful of two-character codes to indicate what they are sending. Those codes are as follows:

YR

Squid sends this to a helper when it needs a new challenge token. This is always the first communication between the two processes. It may also occur at any time that Squid needs a new challenge, due to the auth_param max_challenge_lifetime and max_challenge_uses parameters. The helper should respond with a TT message.

TT challenge

A helper sends this message back to Squid and includes a challenge token. It is sent in response to a YR request. The challenge is base64-encoded, as defined by RFC 2045.

KK credentials

Squid sends this to a helper when it wants to authenticate a user’s credentials. The helper responds with either AF, NA, BH, or LD.

AF username

The helper sends this message back to Squid when the user’s authentication credentials are valid. The helper sends the username with this message because Squid doesn’t try to decode the NTLM Authorization header.

NA reason

The helper sends this message back to Squid when the user’s credentials are invalid. It also includes a “reason” string that Squid can display on an error page.

BH reason

The helper sends this message back to Squid when the validation procedure fails. This might happen, for example, when the helper process is unable to communicate with a Windows NT domain controller. Squid rejects the user’s request.

LD username

This helper-to-Squid response is similar to BH, except that Squid allows the user’s request. Like AF, it returns the username. To use this feature, you must compile Squid with the —enable-ntlm-fail-open option.

Since this protocol is relatively complicated, you’ll probably be better off to start with one of the two skeleton authenticators included in the Squid source distribution. The no_check helper is written in Perl, and fakeauth is written in C. You can find them in the helpers/ntlm_auth directory.

External ACLs

As of Version 2.5, Squid includes a new feature known as external ACLs. These are ACL elements that are implemented in external helper processes. You instruct Squid to write certain information to the helper, which then responds with either OK or ERR. Refer to Section 6.1.3 for a description of the external_acl_type syntax. Here, I’ll only discuss the particular external ACL helper programs that come with the Squid source code.

ip_user

./configure —enable-external-acl-helpers=ip_user

This helper reads usernames and client IP addresses as input. It checks the two values against a configuration file to decide whether or not the combination is valid. To use this ACL helper, you would add lines like this to squid.conf:

external_acl_type ip_user_helper %SRC %LOGIN
    /usr/local/squid/libexec/ip_user -f /usr/local/squid/etc/ip_user.conf
acl AclName external ip_user_helper

%SRC is replaced with the client’s IP address and %LOGIN is replaced with the username for each request. The ip_user.conf configuration file has the following format:

ip_addr[/mask]          user|@group|ALL|NONE

For example:

127.0.0.1               ALL
192.168.1.0/24          bob
10.8.1.0/24             @lusers
172.16.0.0/16           NONE

This configuration file causes ip_user to return OK for any request coming from 127.0.0.1, for Bob’s requests coming from the 192.168.1.0/24 network, for any name in the luser group when the request comes from the 10.8.1.0/24 network, and returns ERR for any request from the 172.16.0.0/16 network. It also returns ERR for any address and username pair that doesn’t appear in the list.

ldap_group

./configure —enable-external-acl-helpers=ldap_group

This helper determines whether or not a user belongs to a particular LDAP group. You specify the LDAP group names on the acl line. It might look like this in your configuration file:

external_acl_type ldap_group_helper %LOGIN /usr/local/squid/libexec/squid_ldap_group
    -b "ou=people,dc=example,dc=com"  ldap.example.com
acl AclName external ldap_group_helper GroupRDN ...

Note that you must have the OpenLDAP (http://www.openldap.org) libraries installed on your system to compile the squid_ldap_group helper program.

unix_group

./configure —enable-external-acl-helpers=unix_group

This helper looks for usernames in the Unix group database (e.g., /etc/group file). You specify the groups to check on the helper command line as follows:

external_acl_type unix_group_helper %LOGIN
    /usr/local/squid/libexec/check_group -g group1 -g group2 ...
acl AclName external unix_group_helper

Alternatively, you can specify groups on the acl line. This allows you to use the same helper for different groups:

external_acl_type unix_group_helper %LOGIN /usr/local/squid/libexec/check_group
acl AclName1 external unix_group_helper group1 ...
acl AclName2 external unix_group_helper group2 ...

wbinfo_group

./configure —enable-external-acl-helpers=wbinfo_group

This helper is a short Perl script that utilizes the wbinfo program from the Samba package. wbinfo is a client for the winbindd daemon. The script expects a single Unix group name following the username on each request. Thus, you must put a group name on the acl line:

external_acl_type wbinfo_group_helper %LOGIN /usr/local/squid/libexec/wbinfo_group.pl
acl AclName external wbinfo_group_helper group

winbind_group

./configure —enable-external-acl-helpers=winbind_group

This helper, written in C, also queries a winbindd server about group membership of Windows NT usernames. It is based on the winbind helpers for Basic and NTLM authentication. You can specify multiple group names on the acl command line:

external_acl_type winbind_group_helper %LOGIN /usr/local/squid/libexec/wb_check_group
acl AclName external winbind_group_helper group1 
               group2 ...

Write Your Own

The external ACL interface offers a lot of flexibility. Chances are you can use it to implement almost any access control check not supported by the built-in methods. Writing an external ACL is a two-step process. First, you must decide what request information the helper program needs to make a decision. Place the appropriate keywords on an external_acl_type line, along with the pathname to the helper program. For example, if you want to write an external ACL helper that uses the client’s IP address, the user’s name, and the value of the Host header, you would write something like:

external_acl_type MyAclHelper %SRC %LOGIN %{Host} 
    /usr/local/squid/libexec/myaclhelper

The second step is to write the myaclhelper program. It must read the request tokens on stdin, make its decision, then write either OK or ERR to stdout. Continuing with the previous example, this Perl script illustrates how to do it:

#!/usr/bin/perl -wl
require 'shellwords.pl';
$|=1;
while (<>) {
    ($ip,$name,$host) = &shellwords;
    if (&valid($ip,$name,$host)) {
        print "OK";
    } else {
        print "ERR";
    }
}

sub valid {
    my $ip = shift;
    my $name = shift;
    my $host = shift;
    ...
}

Refer to Section 6.1.3 for the list of tokens (%SRC, %LOGIN, etc.) that you can pass from Squid to the helper. Note that when a token contains whitespace, Squid wraps it in double quotes. As the example shows, you can use Perl’s shellwords library to parse quoted tokens easily.

Of course, to utilize the external ACL, you must reference it in an acl line. The ACL element is a match whenever the external helper returns OK.

The external ACL helper interface allows you to pass additional information from the helper to Squid (on the OK/ERR line). These take the form of keyword=value pairs. For example:

OK user=hank

Currently, the only keywords that Squid knows about are error and user. If the user value is set, Squid uses it in the access.log. The error value isn’t currently used by Squid.

Exercises

  • Write a fake helper for Basic authentication that always returns either OK or ERR.

  • Use tcpdump or ethereal to capture some HTTP requests. Decode the authorization credentials.

  • If you’re using NTLM, capture some HTTP requests and attempt a replay attack.

  • Kill Squid’s authentication helper processes one-by-one while running tail -f cache.log.

  • Find out what happens to your favorite NTLM-based authenticator when it can’t communicate with the NT domain controller.



[1] Unless you configure a peer with the login=PASS option.

[2] NTLM apparently stands for “NT LanMan” or perhaps “NT Lan Manager.”