User.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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  /* This ip is not in the seen list. Add it. */
110  dlinkAddTail(&new_ipdata->node, &ipdata->node, &ip_list);
111  ++ipcount;
112  /* remove from the source list */
113  dlinkDelete(&new_ipdata->node, &(from->ip_list));
114  ++from->ipcount;
115  }
116  }
117  }
118 }
119 
121 {
122  debugs(29, 5, "Freeing auth_user '" << this << "'.");
123  assert(LockCount() == 0);
124 
125  /* free cached acl results */
126  aclCacheMatchFlush(&proxy_match_cache);
127 
128  /* free seen ip address's */
129  clearIp();
130 
131  if (username_)
132  xfree((char*)username_);
133 
134  /* prevent accidental reuse */
135  auth_type = Auth::AUTH_UNKNOWN;
136 }
137 
138 void
140 {
141  AuthUserIP *ipdata, *tempnode;
142 
143  ipdata = (AuthUserIP *) ip_list.head;
144 
145  while (ipdata) {
146  tempnode = (AuthUserIP *) ipdata->node.next;
147  /* walk the ip list */
148  dlinkDelete(&ipdata->node, &ip_list);
149  delete ipdata;
150  /* catch incipient underflow */
151  assert(ipcount);
152  -- ipcount;
153  ipdata = tempnode;
154  }
155 
156  /* integrity check */
157  assert(ipcount == 0);
158 }
159 
160 void
162 {
163  AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
164 
165  while (ipdata) {
166  /* walk the ip list */
167 
168  if (ipdata->ipaddr == ipaddr) {
169  /* remove the node */
170  dlinkDelete(&ipdata->node, &ip_list);
171  delete ipdata;
172  /* catch incipient underflow */
173  assert(ipcount);
174  -- ipcount;
175  return;
176  }
177 
178  ipdata = (AuthUserIP *) ipdata->node.next;
179  }
180 
181 }
182 
183 void
185 {
186  AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
187  int found = 0;
188 
189  /*
190  * we walk the entire list to prevent the first item in the list
191  * preventing old entries being flushed and locking a user out after
192  * a timeout+reconfigure
193  */
194  while (ipdata) {
195  AuthUserIP *tempnode = (AuthUserIP *) ipdata->node.next;
196  /* walk the ip list */
197 
198  if (ipdata->ipaddr == ipaddr) {
199  /* This ip has already been seen. */
200  found = 1;
201  /* update IP ttl */
203  } else if (ipdata->ip_expiretime <= squid_curtime) {
204  /* This IP has expired - remove from the seen list */
205  dlinkDelete(&ipdata->node, &ip_list);
206  delete ipdata;
207  /* catch incipient underflow */
208  assert(ipcount);
209  -- ipcount;
210  }
211 
212  ipdata = tempnode;
213  }
214 
215  if (found)
216  return;
217 
218  /* This ip is not in the seen list */
219  ipdata = new AuthUserIP(ipaddr, squid_curtime + Auth::TheConfig.ipTtl);
220 
221  dlinkAddTail(ipdata, &ipdata->node, &ip_list);
222 
223  ++ipcount;
224 
225  debugs(29, 2, "user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")");
226 }
227 
228 SBuf
229 Auth::User::BuildUserKey(const char *username, const char *realm)
230 {
231  SBuf key;
232  if (realm)
233  key.Printf("%s:%s", username, realm);
234  else
235  key.append(username, strlen(username));
236  return key;
237 }
238 
242 void
244 {
245  auto userlist = authenticateCachedUsersList();
246  storeAppendPrintf(output, "Cached Usernames: %d", static_cast<int32_t>(userlist.size()));
247  storeAppendPrintf(output, "\n%-15s %-9s %-9s %-9s %s\t%s\n",
248  "Type",
249  "State",
250  "Check TTL",
251  "Cache TTL",
252  "Username", "Key");
253  storeAppendPrintf(output, "--------------- --------- --------- --------- ------------------------------\n");
254  for ( auto auth_user : userlist ) {
255  storeAppendPrintf(output, "%-15s %-9s %-9d %-9d %s\t" SQUIDSBUFPH "\n",
256  Auth::Type_str[auth_user->auth_type],
257  CredentialState_str[auth_user->credentials()],
258  auth_user->ttl(),
259  static_cast<int32_t>(auth_user->expiretime - squid_curtime + Auth::TheConfig.credentialsTtl),
260  auth_user->username(),
261  SQUIDSBUFPRINT(auth_user->userKey())
262  );
263  }
264 }
265 
266 void
267 Auth::User::username(char const *aString)
268 {
269  if (aString) {
270  assert(!username_);
271  username_ = xstrdup(aString);
272  // NP: param #2 is working around a c_str() data-copy performance regression
273  userKey_ = BuildUserKey(username_, (!requestRealm_.isEmpty() ? requestRealm_.c_str() : nullptr));
274  } else {
275  safe_free(username_);
276  userKey_.clear();
277  }
278 }
279 
HTTP Authentication.
Definition: Config.h:18
~User() override
Definition: User.cc:120
static SBuf BuildUserKey(const char *username, const char *realm)
Definition: User.cc:229
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:243
#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:139
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:161
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:184
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