]>
Commit | Line | Data |
---|---|---|
351fe86d AR |
1 | #include "squid.h" |
2 | #include "HttpRequest.h" | |
3 | #include "HttpReply.h" | |
4 | #include "client_side.h" | |
5 | #include "auth/UserRequest.h" | |
6 | #include "auth/AclProxyAuth.h" | |
7 | #include "acl/FilledChecklist.h" | |
8 | ||
9 | CBDATA_CLASS_INIT(ACLFilledChecklist); | |
10 | ||
11 | #if MOVED | |
12 | int | |
13 | ACLFilledChecklist::authenticated() | |
14 | { | |
15 | http_hdr_type headertype; | |
16 | ||
17 | if (NULL == request) { | |
18 | fatal ("requiresRequest SHOULD have been true for this ACL!!"); | |
19 | return 0; | |
20 | } else if (request->flags.accelerated) { | |
21 | /* WWW authorization on accelerated requests */ | |
22 | headertype = HDR_AUTHORIZATION; | |
23 | } else if (request->flags.intercepted || request->flags.spoof_client_ip) { | |
24 | debugs(28, DBG_IMPORTANT, HERE << " authentication not applicable on intercepted requests."); | |
25 | return -1; | |
26 | } else { | |
27 | /* Proxy authorization on proxy requests */ | |
28 | headertype = HDR_PROXY_AUTHORIZATION; | |
29 | } | |
30 | ||
31 | /* get authed here */ | |
32 | /* Note: this fills in auth_user_request when applicable */ | |
33 | /* | |
34 | * DPW 2007-05-08 | |
35 | * tryToAuthenticateAndSetAuthUser used to try to lock and | |
36 | * unlock auth_user_request on our behalf, but it was too | |
37 | * ugly and hard to follow. Now we do our own locking here. | |
38 | * | |
39 | * I'm not sure what tryToAuthenticateAndSetAuthUser does when | |
40 | * auth_user_request is set before calling. I'm tempted to | |
41 | * unlock and set it to NULL, but it seems safer to save the | |
42 | * pointer before calling and unlock it afterwards. If the | |
43 | * pointer doesn't change then its a no-op. | |
44 | */ | |
45 | AuthUserRequest *old_auth_user_request = auth_user_request; | |
46 | auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr); | |
47 | if (auth_user_request) | |
48 | AUTHUSERREQUESTLOCK(auth_user_request, "ACLFilledChecklist"); | |
49 | AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLFilledChecklist"); | |
50 | switch (result) { | |
51 | ||
52 | case AUTH_ACL_CANNOT_AUTHENTICATE: | |
53 | debugs(28, 4, "aclMatchAcl: returning 0 user authenticated but not authorised."); | |
54 | return 0; | |
55 | ||
56 | case AUTH_AUTHENTICATED: | |
57 | ||
58 | return 1; | |
59 | break; | |
60 | ||
61 | case AUTH_ACL_HELPER: | |
62 | debugs(28, 4, "aclMatchAcl: returning 0 sending credentials to helper."); | |
63 | changeState (ProxyAuthLookup::Instance()); | |
64 | return 0; | |
65 | ||
66 | case AUTH_ACL_CHALLENGE: | |
67 | debugs(28, 4, "aclMatchAcl: returning 0 sending authentication challenge."); | |
68 | changeState (ProxyAuthNeeded::Instance()); | |
69 | return 0; | |
70 | ||
71 | default: | |
72 | fatal("unexpected authenticateAuthenticate reply\n"); | |
73 | return 0; | |
74 | } | |
75 | } | |
76 | #endif | |
77 | ||
78 | void | |
79 | ACLFilledChecklist::checkCallback(allow_t answer) | |
80 | { | |
81 | debugs(28, 5, "ACLFilledChecklist::checkCallback: " << this << " answer=" << answer); | |
82 | ||
83 | /* During reconfigure, we can end up not finishing call | |
84 | * sequences into the auth code */ | |
85 | ||
86 | if (auth_user_request) { | |
87 | /* the filled_checklist lock */ | |
88 | AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist"); | |
89 | /* it might have been connection based */ | |
90 | assert(conn() != NULL); | |
91 | /* | |
92 | * DPW 2007-05-08 | |
93 | * yuck, this make me uncomfortable. why do this here? | |
94 | * ConnStateData will do its own unlocking. | |
95 | */ | |
96 | AUTHUSERREQUESTUNLOCK(conn()->auth_user_request, "conn via ACLFilledChecklist"); | |
97 | conn()->auth_type = AUTH_BROKEN; | |
98 | } | |
99 | ||
100 | ACLFilledChecklist::checkCallback(answer); // may delete us | |
101 | } | |
102 | ||
103 | ||
104 | void * | |
105 | ACLFilledChecklist::operator new (size_t size) | |
106 | { | |
107 | assert (size == sizeof(ACLFilledChecklist)); | |
108 | CBDATA_INIT_TYPE(ACLFilledChecklist); | |
109 | ACLFilledChecklist *result = cbdataAlloc(ACLFilledChecklist); | |
110 | return result; | |
111 | } | |
112 | ||
113 | void | |
114 | ACLFilledChecklist::operator delete (void *address) | |
115 | { | |
116 | ACLFilledChecklist *t = static_cast<ACLFilledChecklist *>(address); | |
117 | cbdataFree(t); | |
118 | } | |
119 | ||
120 | ||
121 | ACLFilledChecklist::ACLFilledChecklist() : | |
122 | dst_peer(NULL), | |
123 | request (NULL), | |
124 | reply (NULL), | |
125 | auth_user_request (NULL), | |
126 | #if SQUID_SNMP | |
127 | snmp_community(NULL), | |
128 | #endif | |
129 | #if USE_SSL | |
130 | ssl_error(0), | |
131 | #endif | |
132 | extacl_entry (NULL), | |
133 | conn_(NULL), | |
134 | fd_(-1), | |
135 | destinationDomainChecked_(false), | |
136 | sourceDomainChecked_(false) | |
137 | { | |
138 | my_addr.SetEmpty(); | |
139 | src_addr.SetEmpty(); | |
140 | dst_addr.SetEmpty(); | |
141 | rfc931[0] = '\0'; | |
142 | } | |
143 | ||
144 | ||
145 | ACLFilledChecklist::~ACLFilledChecklist() | |
146 | { | |
147 | assert (!asyncInProgress()); | |
148 | ||
149 | if (extacl_entry) | |
150 | cbdataReferenceDone(extacl_entry); | |
151 | ||
152 | HTTPMSGUNLOCK(request); | |
153 | ||
154 | HTTPMSGUNLOCK(reply); | |
155 | ||
156 | // no auth_user_request in builds without any Authentication configured | |
157 | if (auth_user_request) | |
158 | AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist destructor"); | |
159 | ||
160 | cbdataReferenceDone(conn_); | |
161 | ||
162 | debugs(28, 4, HERE << "ACLFilledChecklist destroyed " << this); | |
163 | } | |
164 | ||
165 | ||
166 | ConnStateData * | |
167 | ACLFilledChecklist::conn() const | |
168 | { | |
169 | return conn_; | |
170 | } | |
171 | ||
172 | void | |
173 | ACLFilledChecklist::conn(ConnStateData *aConn) | |
174 | { | |
175 | assert (conn() == NULL); | |
176 | conn_ = cbdataReference(aConn); | |
177 | } | |
178 | ||
179 | int | |
180 | ACLFilledChecklist::fd() const | |
181 | { | |
182 | return conn_ != NULL ? conn_->fd : fd_; | |
183 | } | |
184 | ||
185 | void | |
186 | ACLFilledChecklist::fd(int aDescriptor) | |
187 | { | |
188 | assert(!conn() || conn()->fd == aDescriptor); | |
189 | fd_ = aDescriptor; | |
190 | } | |
191 | ||
192 | bool | |
193 | ACLFilledChecklist::destinationDomainChecked() const | |
194 | { | |
195 | return destinationDomainChecked_; | |
196 | } | |
197 | ||
198 | void | |
199 | ACLFilledChecklist::markDestinationDomainChecked() | |
200 | { | |
201 | assert (!finished() && !destinationDomainChecked()); | |
202 | destinationDomainChecked_ = true; | |
203 | } | |
204 | ||
205 | bool | |
206 | ACLFilledChecklist::sourceDomainChecked() const | |
207 | { | |
208 | return sourceDomainChecked_; | |
209 | } | |
210 | ||
211 | void | |
212 | ACLFilledChecklist::markSourceDomainChecked() | |
213 | { | |
214 | assert (!finished() && !sourceDomainChecked()); | |
215 | sourceDomainChecked_ = true; | |
216 | } | |
217 | ||
218 | /* | |
219 | * There are two common ACLFilledChecklist lifecycles paths: | |
220 | * | |
221 | * A) Using aclCheckFast(): The caller creates an ACLFilledChecklist object | |
222 | * on stack and calls aclCheckFast(). | |
223 | * | |
224 | * B) Using aclNBCheck() and callbacks: The caller allocates an | |
225 | * ACLFilledChecklist object (via operator new) and passes it to | |
226 | * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(), | |
227 | * which will invoke the callback function as requested by the | |
228 | * original caller of aclNBCheck(). This callback function must | |
229 | * *not* delete the list. After the callback function returns, | |
230 | * checkCallback() will delete the list (i.e., self). | |
231 | */ | |
232 | ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *request, const char *ident): | |
233 | dst_peer(NULL), | |
234 | request(NULL), | |
235 | reply(NULL), | |
236 | auth_user_request(NULL), | |
237 | #if SQUID_SNMP | |
238 | snmp_community(NULL), | |
239 | #endif | |
240 | #if USE_SSL | |
241 | ssl_error(0), | |
242 | #endif | |
243 | extacl_entry (NULL), | |
244 | conn_(NULL), | |
245 | fd_(-1), | |
246 | destinationDomainChecked_(false), | |
247 | sourceDomainChecked_(false) | |
248 | { | |
249 | my_addr.SetEmpty(); | |
250 | src_addr.SetEmpty(); | |
251 | dst_addr.SetEmpty(); | |
252 | rfc931[0] = '\0'; | |
253 | ||
254 | // cbdataReferenceDone() is in either fastCheck() or the destructor | |
255 | if (A) | |
256 | accessList = cbdataReference(A); | |
257 | ||
258 | if (request != NULL) { | |
259 | request = HTTPMSGLOCK(request); | |
260 | #if FOLLOW_X_FORWARDED_FOR | |
261 | if (Config.onoff.acl_uses_indirect_client) | |
262 | src_addr = request->indirect_client_addr; | |
263 | else | |
264 | #endif /* FOLLOW_X_FORWARDED_FOR */ | |
265 | src_addr = request->client_addr; | |
266 | my_addr = request->my_addr; | |
267 | } | |
268 | ||
269 | #if USE_IDENT | |
270 | if (ident) | |
271 | xstrncpy(rfc931, ident, USER_IDENT_SZ); | |
272 | #endif | |
273 | } | |
274 |