Squid Web Cache master
Loading...
Searching...
No Matches
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"
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
23Auth::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
43void
45{
46 credentials_state = newCreds;
47}
48
58void
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
139void
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
161void
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
184void
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
229SBuf
230Auth::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
243void
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
267void
268Auth::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
time_t squid_curtime
#define SQUIDSBUFPH
Definition SBuf.h:31
#define SQUIDSBUFPRINT(s)
Definition SBuf.h:32
#define assert(EX)
Definition assert.h:17
std::vector< Auth::User::Pointer > authenticateCachedUsersList()
Definition Gadgets.cc:108
Ip::Address ipaddr
IP address this user authenticated from.
Definition UserRequest.h:47
dlink_node node
Definition UserRequest.h:44
time_t ip_expiretime
Definition UserRequest.h:53
time_t credentialsTtl
the authenticate_ttl
Definition Config.h:43
time_t ipTtl
the authenticate_ip_ttl
Definition Config.h:46
NotePairs notes
list of key=value pairs the helper produced
Definition User.h:56
void absorb(Auth::User::Pointer from)
Definition User.cc:59
dlink_list ip_list
Definition User.h:121
size_t ipcount
Definition User.h:52
CredentialState credentials() const
Definition User.cc:38
static void CredentialsCacheStats(StoreEntry *output)
Definition User.cc:244
char const * username() const
Definition User.h:62
static SBuf BuildUserKey(const char *username, const char *realm)
Definition User.cc:230
User(Auth::SchemeConfig *, const char *requestRealm)
Definition User.cc:23
dlink_list proxy_match_cache
Definition User.h:51
~User() override
Definition User.cc:121
void clearIp()
Definition User.cc:140
void removeIp(Ip::Address)
Definition User.cc:162
void addIp(Ip::Address)
Definition User.cc:185
Definition SBuf.h:94
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition SBuf.cc:214
SBuf & append(const SBuf &S)
Definition SBuf.cc:185
A const & max(A const &lhs, A const &rhs)
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
void aclCacheMatchFlush(dlink_list *cache)
Definition Acl.cc:425
HTTP Authentication.
Definition Config.h:19
@ AUTH_UNKNOWN
Definition Type.h:18
const char * Type_str[]
const char * CredentialState_str[]
Auth::Config TheConfig
Definition Config.cc:15
#define xfree
#define xstrdup
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition store.cc:855
#define safe_free(x)
Definition xalloc.h:73