User.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 29 Authenticator */
10 
11 #include "squid.h"
12 #include "acl/Acl.h"
13 #include "acl/Gadgets.h"
14 #include "auth/Config.h"
15 #include "auth/CredentialsCache.h"
16 #include "auth/Gadgets.h"
17 #include "auth/User.h"
18 #include "auth/UserRequest.h"
19 #include "event.h"
20 #include "globals.h"
21 #include "Store.h"
22 
23 Auth::User::User(Auth::SchemeConfig *aConfig, const char *aRequestRealm) :
24  auth_type(Auth::AUTH_UNKNOWN),
25  config(aConfig),
26  ipcount(0),
27  expiretime(0),
28  credentials_state(Auth::Unchecked),
29  username_(nullptr),
30  requestRealm_(aRequestRealm)
31 {
33  ip_list.head = ip_list.tail = nullptr;
34  debugs(29, 5, "Initialised auth_user '" << this << "'.");
35 }
36 
39 {
40  return credentials_state;
41 }
42 
43 void
45 {
46  credentials_state = newCreds;
47 }
48 
58 void
60 {
61  /*
62  * XXX Incomplete: it should merge in hash references too and ask the module to merge in scheme data
63  * dlink_list proxy_match_cache;
64  */
65 
66  debugs(29, 5, "auth_user '" << from << "' into auth_user '" << this << "'.");
67 
68  // combine the helper response annotations. Ensuring no duplicates are copied.
69  notes.appendNewOnly(&from->notes);
70 
71  /* absorb the list of IP address sources (for max_user_ip controls) */
72  AuthUserIP *new_ipdata;
73  while (from->ip_list.head != nullptr) {
74  new_ipdata = static_cast<AuthUserIP *>(from->ip_list.head->data);
75 
76  /* If this IP has expired - ignore the expensive merge actions. */
77  if (new_ipdata->ip_expiretime <= squid_curtime) {
78  /* This IP has expired - remove from the source list */
79  dlinkDelete(&new_ipdata->node, &(from->ip_list));
80  delete new_ipdata;
81  /* catch incipient underflow */
82  -- from->ipcount;
83  } else {
84  /* add to our list. replace if already present. */
85  AuthUserIP *ipdata = static_cast<AuthUserIP *>(ip_list.head->data);
86  bool found = false;
87  while (ipdata) {
88  AuthUserIP *tempnode = static_cast<AuthUserIP *>(ipdata->node.next->data);
89 
90  if (ipdata->ipaddr == new_ipdata->ipaddr) {
91  /* This IP has already been seen. */
92  found = true;
93  /* update IP ttl and stop searching. */
94  ipdata->ip_expiretime = max(ipdata->ip_expiretime, new_ipdata->ip_expiretime);
95  break;
96  } else if (ipdata->ip_expiretime <= squid_curtime) {
97  /* This IP has expired - cleanup the destination list */
98  dlinkDelete(&ipdata->node, &ip_list);
99  delete ipdata;
100  /* catch incipient underflow */
101  assert(ipcount);
102  -- ipcount;
103  }
104 
105  ipdata = tempnode;
106  }
107 
108  if (!found) {
109  /* remove from the source list */
110  dlinkDelete(&new_ipdata->node, &(from->ip_list));
111  assert(from->ipcount);
112  --from->ipcount;
113  /* This ip is not in the seen list. Add it. */
114  dlinkAddTail(new_ipdata, &new_ipdata->node, &ip_list);
115  ++ipcount;
116  }
117  }
118  }
119 }
120 
122 {
123  debugs(29, 5, "Freeing auth_user '" << this << "'.");
124  assert(LockCount() == 0);
125 
126  /* free cached acl results */
127  aclCacheMatchFlush(&proxy_match_cache);
128 
129  /* free seen ip address's */
130  clearIp();
131 
132  if (username_)
133  xfree((char*)username_);
134 
135  /* prevent accidental reuse */
136  auth_type = Auth::AUTH_UNKNOWN;
137 }
138 
139 void
141 {
142  AuthUserIP *ipdata, *tempnode;
143 
144  ipdata = (AuthUserIP *) ip_list.head;
145 
146  while (ipdata) {
147  tempnode = (AuthUserIP *) ipdata->node.next;
148  /* walk the ip list */
149  dlinkDelete(&ipdata->node, &ip_list);
150  delete ipdata;
151  /* catch incipient underflow */
152  assert(ipcount);
153  -- ipcount;
154  ipdata = tempnode;
155  }
156 
157  /* integrity check */
158  assert(ipcount == 0);
159 }
160 
161 void
163 {
164  AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
165 
166  while (ipdata) {
167  /* walk the ip list */
168 
169  if (ipdata->ipaddr == ipaddr) {
170  /* remove the node */
171  dlinkDelete(&ipdata->node, &ip_list);
172  delete ipdata;
173  /* catch incipient underflow */
174  assert(ipcount);
175  -- ipcount;
176  return;
177  }
178 
179  ipdata = (AuthUserIP *) ipdata->node.next;
180  }
181 
182 }
183 
184 void
186 {
187  AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
188  int found = 0;
189 
190  /*
191  * we walk the entire list to prevent the first item in the list
192  * preventing old entries being flushed and locking a user out after
193  * a timeout+reconfigure
194  */
195  while (ipdata) {
196  AuthUserIP *tempnode = (AuthUserIP *) ipdata->node.next;
197  /* walk the ip list */
198 
199  if (ipdata->ipaddr == ipaddr) {
200  /* This ip has already been seen. */
201  found = 1;
202  /* update IP ttl */
204  } else if (ipdata->ip_expiretime <= squid_curtime) {
205  /* This IP has expired - remove from the seen list */
206  dlinkDelete(&ipdata->node, &ip_list);
207  delete ipdata;
208  /* catch incipient underflow */
209  assert(ipcount);
210  -- ipcount;
211  }
212 
213  ipdata = tempnode;
214  }
215 
216  if (found)
217  return;
218 
219  /* This ip is not in the seen list */
220  ipdata = new AuthUserIP(ipaddr, squid_curtime + Auth::TheConfig.ipTtl);
221 
222  dlinkAddTail(ipdata, &ipdata->node, &ip_list);
223 
224  ++ipcount;
225 
226  debugs(29, 2, "user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")");
227 }
228 
229 SBuf
230 Auth::User::BuildUserKey(const char *username, const char *realm)
231 {
232  SBuf key;
233  if (realm)
234  key.Printf("%s:%s", username, realm);
235  else
236  key.append(username, strlen(username));
237  return key;
238 }
239 
243 void
245 {
246  auto userlist = authenticateCachedUsersList();
247  storeAppendPrintf(output, "Cached Usernames: %d", static_cast<int32_t>(userlist.size()));
248  storeAppendPrintf(output, "\n%-15s %-9s %-9s %-9s %s\t%s\n",
249  "Type",
250  "State",
251  "Check TTL",
252  "Cache TTL",
253  "Username", "Key");
254  storeAppendPrintf(output, "--------------- --------- --------- --------- ------------------------------\n");
255  for ( auto auth_user : userlist ) {
256  storeAppendPrintf(output, "%-15s %-9s %-9d %-9d %s\t" SQUIDSBUFPH "\n",
257  Auth::Type_str[auth_user->auth_type],
258  CredentialState_str[auth_user->credentials()],
259  auth_user->ttl(),
260  static_cast<int32_t>(auth_user->expiretime - squid_curtime + Auth::TheConfig.credentialsTtl),
261  auth_user->username(),
262  SQUIDSBUFPRINT(auth_user->userKey())
263  );
264  }
265 }
266 
267 void
268 Auth::User::username(char const *aString)
269 {
270  if (aString) {
271  assert(!username_);
272  username_ = xstrdup(aString);
273  // NP: param #2 is working around a c_str() data-copy performance regression
274  userKey_ = BuildUserKey(username_, (!requestRealm_.isEmpty() ? requestRealm_.c_str() : nullptr));
275  } else {
276  safe_free(username_);
277  userKey_.clear();
278  }
279 }
280 
HTTP Authentication.
Definition: Config.h:18
~User() override
Definition: User.cc:121
static SBuf BuildUserKey(const char *username, const char *realm)
Definition: User.cc:230
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
Definition: SBuf.h:93
#define xstrdup
const A & max(A const &lhs, A const &rhs)
Auth::Config TheConfig
Definition: Config.cc:15
time_t ip_expiretime
Definition: UserRequest.h:53
@ AUTH_UNKNOWN
Definition: Type.h:18
Ip::Address ipaddr
IP address this user authenticated from.
Definition: UserRequest.h:47
static void CredentialsCacheStats(StoreEntry *output)
Definition: User.cc:244
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
dlink_node node
Definition: UserRequest.h:44
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:214
void clearIp()
Definition: User.cc:140
NotePairs notes
list of key=value pairs the helper produced
Definition: User.h:56
#define safe_free(x)
Definition: xalloc.h:73
#define assert(EX)
Definition: assert.h:17
User(Auth::SchemeConfig *, const char *requestRealm)
Definition: User.cc:23
const char * username() const
Definition: User.h:62
void aclCacheMatchFlush(dlink_list *cache)
Definition: Acl.cc:425
const char * CredentialState_str[]
time_t squid_curtime
Definition: stub_libtime.cc:20
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
#define xfree
std::vector< Auth::User::Pointer > authenticateCachedUsersList()
Definition: Gadgets.cc:108
void removeIp(Ip::Address)
Definition: User.cc:162
dlink_list ip_list
Definition: User.h:121
time_t credentialsTtl
the authenticate_ttl
Definition: Config.h:43
time_t ipTtl
the authenticate_ip_ttl
Definition: Config.h:46
CredentialState credentials() const
Definition: User.cc:38
size_t ipcount
Definition: User.h:52
const char * Type_str[]
void addIp(Ip::Address)
Definition: User.cc:185
void absorb(Auth::User::Pointer from)
Definition: User.cc:59
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
#define SQUIDSBUFPH
Definition: SBuf.h:31
dlink_list proxy_match_cache
Definition: User.h:51

 

Introduction

Documentation

Support

Miscellaneous