]>
Commit | Line | Data |
---|---|---|
225b7b10 | 1 | /* |
5a363fb1 | 2 | * $Id: ACLChecklist.cc,v 1.40 2007/07/19 00:35:27 hno Exp $ |
225b7b10 | 3 | * |
4 | * DEBUG: section 28 Access Control | |
5 | * AUTHOR: Duane Wessels | |
6 | * | |
7 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
8 | * ---------------------------------------------------------- | |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from | |
11 | * the Internet community; see the CONTRIBUTORS file for full | |
12 | * details. Many organizations have provided support for Squid's | |
13 | * development; see the SPONSORS file for full details. Squid is | |
14 | * Copyrighted (C) 2001 by the Regents of the University of | |
15 | * California; see the COPYRIGHT file for full details. Squid | |
16 | * incorporates software developed and/or copyrighted by other | |
17 | * sources; see the CREDITS file for full details. | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the GNU General Public License as published by | |
21 | * the Free Software Foundation; either version 2 of the License, or | |
22 | * (at your option) any later version. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, | |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License | |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
32 | * | |
33 | * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org> | |
34 | */ | |
35 | ||
36 | #include "squid.h" | |
37 | #include "ACLChecklist.h" | |
225b7b10 | 38 | #include "HttpRequest.h" |
7dc5f514 | 39 | #include "HttpReply.h" |
225b7b10 | 40 | #include "authenticate.h" |
225b7b10 | 41 | #include "ACLProxyAuth.h" |
a46d2c0e | 42 | #include "client_side.h" |
f5691f9c | 43 | #include "AuthUserRequest.h" |
225b7b10 | 44 | |
45 | int | |
46 | ACLChecklist::authenticated() | |
47 | { | |
48 | http_hdr_type headertype; | |
62e76326 | 49 | |
225b7b10 | 50 | if (NULL == request) { |
62e76326 | 51 | fatal ("requiresRequest SHOULD have been true for this ACL!!"); |
52 | return 0; | |
d048c262 | 53 | } else if (request->flags.accelerated) { |
62e76326 | 54 | /* WWW authorization on accelerated requests */ |
55 | headertype = HDR_AUTHORIZATION; | |
d048c262 | 56 | } else if (request->flags.transparent) { |
bf8fe701 | 57 | debugs(28, 1, "ACHChecklist::authenticated: authentication not applicable on transparently intercepted requests."); |
62e76326 | 58 | return -1; |
d048c262 | 59 | } else { |
60 | /* Proxy authorization on proxy requests */ | |
61 | headertype = HDR_PROXY_AUTHORIZATION; | |
225b7b10 | 62 | } |
62e76326 | 63 | |
225b7b10 | 64 | /* get authed here */ |
6bf4f823 | 65 | /* Note: this fills in auth_user_request when applicable */ |
4f0ef8e8 | 66 | /* |
67 | * DPW 2007-05-08 | |
68 | * tryToAuthenticateAndSetAuthUser used to try to lock and | |
69 | * unlock auth_user_request on our behalf, but it was too | |
70 | * ugly and hard to follow. Now we do our own locking here. | |
71 | * | |
72 | * I'm not sure what tryToAuthenticateAndSetAuthUser does when | |
73 | * auth_user_request is set before calling. I'm tempted to | |
74 | * unlock and set it to NULL, but it seems safer to save the | |
75 | * pointer before calling and unlock it afterwards. If the | |
76 | * pointer doesn't change then its a no-op. | |
77 | */ | |
78 | AuthUserRequest *old_auth_user_request = auth_user_request; | |
79 | auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr); | |
80 | if (auth_user_request) | |
81 | AUTHUSERREQUESTLOCK(auth_user_request, "ACLChecklist"); | |
82 | AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLChecklist"); | |
83 | switch (result) { | |
62e76326 | 84 | |
225b7b10 | 85 | case AUTH_ACL_CANNOT_AUTHENTICATE: |
bf8fe701 | 86 | debugs(28, 4, "aclMatchAcl: returning 0 user authenticated but not authorised."); |
62e76326 | 87 | return 0; |
88 | ||
225b7b10 | 89 | case AUTH_AUTHENTICATED: |
8777d90e | 90 | |
62e76326 | 91 | return 1; |
92 | break; | |
93 | ||
225b7b10 | 94 | case AUTH_ACL_HELPER: |
bf8fe701 | 95 | debugs(28, 4, "aclMatchAcl: returning 0 sending credentials to helper."); |
62e76326 | 96 | changeState (ProxyAuthLookup::Instance()); |
97 | return 0; | |
98 | ||
225b7b10 | 99 | case AUTH_ACL_CHALLENGE: |
bf8fe701 | 100 | debugs(28, 4, "aclMatchAcl: returning 0 sending authentication challenge."); |
62e76326 | 101 | changeState (ProxyAuthNeeded::Instance()); |
102 | return 0; | |
103 | ||
225b7b10 | 104 | default: |
62e76326 | 105 | fatal("unexpected authenticateAuthenticate reply\n"); |
106 | return 0; | |
225b7b10 | 107 | } |
108 | } | |
109 | ||
110 | allow_t const & | |
111 | ACLChecklist::currentAnswer() const | |
112 | { | |
113 | return allow_; | |
114 | } | |
115 | ||
116 | void | |
117 | ACLChecklist::currentAnswer(allow_t const newAnswer) | |
118 | { | |
119 | allow_ = newAnswer; | |
120 | } | |
62e76326 | 121 | |
225b7b10 | 122 | void |
123 | ACLChecklist::check() | |
124 | { | |
b6f25d16 | 125 | if (checking()) |
62e76326 | 126 | return; |
127 | ||
225b7b10 | 128 | /* deny if no rules present */ |
129 | currentAnswer(ACCESS_DENIED); | |
62e76326 | 130 | |
225b7b10 | 131 | /* NOTE: This holds a cbdata reference to the current access_list |
132 | * entry, not the whole list. | |
133 | */ | |
134 | while (accessList != NULL) { | |
62e76326 | 135 | /* |
136 | * If the _acl_access is no longer valid (i.e. its been | |
137 | * freed because of a reconfigure), then bail on this | |
138 | * access check. For now, return ACCESS_DENIED. | |
139 | */ | |
140 | ||
141 | if (!cbdataReferenceValid(accessList)) { | |
142 | cbdataReferenceDone(accessList); | |
bf8fe701 | 143 | debugs(28, 4, "ACLChecklist::check: " << this << " accessList is invalid"); |
62e76326 | 144 | continue; |
145 | } | |
146 | ||
147 | checking (true); | |
148 | checkAccessList(); | |
149 | checking (false); | |
150 | ||
151 | if (asyncInProgress()) { | |
152 | return; | |
153 | } | |
154 | ||
155 | if (finished()) { | |
156 | /* | |
157 | * We are done. Either the request | |
158 | * is allowed, denied, requires authentication. | |
159 | */ | |
bf8fe701 | 160 | debugs(28, 3, "ACLChecklist::check: " << this << " match found, calling back with " << currentAnswer()); |
62e76326 | 161 | cbdataReferenceDone(accessList); /* A */ |
162 | checkCallback(currentAnswer()); | |
163 | /* From here on in, this may be invalid */ | |
164 | return; | |
165 | } | |
166 | ||
167 | /* | |
168 | * Reference the next access entry | |
169 | */ | |
170 | const acl_access *A = accessList; | |
171 | ||
172 | assert (A); | |
173 | ||
174 | accessList = cbdataReference(A->next); | |
175 | ||
176 | cbdataReferenceDone(A); | |
225b7b10 | 177 | } |
62e76326 | 178 | |
225b7b10 | 179 | /* dropped off the end of the list */ |
bf8fe701 | 180 | debugs(28, 3, "ACLChecklist::check: " << this << |
181 | " NO match found, returning " << | |
182 | (currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED)); | |
62e76326 | 183 | |
225b7b10 | 184 | checkCallback(currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED); |
185 | } | |
186 | ||
187 | bool | |
188 | ACLChecklist::asyncInProgress() const | |
189 | { | |
190 | return async_; | |
191 | } | |
192 | ||
193 | void | |
194 | ACLChecklist::asyncInProgress(bool const newAsync) | |
195 | { | |
3841dd46 | 196 | assert (!finished() && !(asyncInProgress() && newAsync)); |
225b7b10 | 197 | async_ = newAsync; |
bf8fe701 | 198 | debugs(28, 3, "ACLChecklist::asyncInProgress: " << this << |
199 | " async set to " << async_); | |
225b7b10 | 200 | } |
201 | ||
202 | bool | |
203 | ACLChecklist::finished() const | |
204 | { | |
205 | return finished_; | |
206 | } | |
207 | ||
208 | void | |
209 | ACLChecklist::markFinished() | |
210 | { | |
3841dd46 | 211 | assert (!finished() && !asyncInProgress()); |
225b7b10 | 212 | finished_ = true; |
bf8fe701 | 213 | debugs(28, 3, "ACLChecklist::markFinished: " << this << |
214 | " checklist processing finished"); | |
225b7b10 | 215 | } |
216 | ||
c35e260d | 217 | void |
218 | ACLChecklist::preCheck() | |
219 | { | |
bf8fe701 | 220 | debugs(28, 3, "ACLChecklist::preCheck: " << this << " checking '" << accessList->cfgline << "'"); |
c35e260d | 221 | /* what is our result on a match? */ |
222 | currentAnswer(accessList->allow); | |
223 | } | |
224 | ||
225b7b10 | 225 | void |
226 | ACLChecklist::checkAccessList() | |
227 | { | |
c35e260d | 228 | preCheck(); |
225b7b10 | 229 | /* does the current AND clause match */ |
ef1955a5 | 230 | matchAclListSlow(accessList->aclList); |
225b7b10 | 231 | } |
232 | ||
233 | void | |
234 | ACLChecklist::checkForAsync() | |
235 | { | |
3841dd46 | 236 | asyncState()->checkForAsync(this); |
225b7b10 | 237 | } |
238 | ||
239 | void | |
240 | ACLChecklist::checkCallback(allow_t answer) | |
241 | { | |
242 | PF *callback_; | |
243 | void *cbdata_; | |
bf8fe701 | 244 | debugs(28, 3, "ACLChecklist::checkCallback: " << this << " answer=" << answer); |
245 | ||
6bf4f823 | 246 | /* During reconfigure, we can end up not finishing call |
247 | * sequences into the auth code */ | |
248 | ||
249 | if (auth_user_request) { | |
250 | /* the checklist lock */ | |
4f0ef8e8 | 251 | AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLChecklist"); |
6bf4f823 | 252 | /* it might have been connection based */ |
4d3a24ca | 253 | assert(conn() != NULL); |
4f0ef8e8 | 254 | /* |
255 | * DPW 2007-05-08 | |
256 | * yuck, this make me uncomfortable. why do this here? | |
257 | * ConnStateData will do its own unlocking. | |
258 | */ | |
259 | AUTHUSERREQUESTUNLOCK(conn()->auth_user_request, "conn via ACLChecklist"); | |
6bf4f823 | 260 | conn()->auth_type = AUTH_BROKEN; |
6bf4f823 | 261 | } |
62e76326 | 262 | |
225b7b10 | 263 | callback_ = callback; |
264 | callback = NULL; | |
62e76326 | 265 | |
225b7b10 | 266 | if (cbdataReferenceValidDone(callback_data, &cbdata_)) |
62e76326 | 267 | callback_(answer, cbdata_); |
268 | ||
00d77d6b | 269 | delete this; |
225b7b10 | 270 | } |
62e76326 | 271 | |
5ea3aff4 | 272 | void |
273 | ACLChecklist::matchAclListSlow(const acl_list * list) | |
274 | { | |
275 | matchAclList(list, false); | |
276 | } | |
277 | ||
48071869 | 278 | void |
5dee515e | 279 | ACLChecklist::matchAclList(const acl_list * head, bool const fast) |
225b7b10 | 280 | { |
281 | PROF_start(aclMatchAclList); | |
282 | const acl_list *node = head; | |
62e76326 | 283 | |
ba63443a | 284 | finished_ = false; |
285 | ||
225b7b10 | 286 | while (node) { |
62e76326 | 287 | bool nodeMatched = node->matches(this); |
288 | ||
289 | if (fast) | |
290 | changeState(NullState::Instance()); | |
291 | ||
ff3f3722 | 292 | if (finished()) { |
293 | PROF_stop(aclMatchAclList); | |
294 | return; | |
295 | } | |
296 | ||
62e76326 | 297 | if (!nodeMatched || state_ != NullState::Instance()) { |
bf8fe701 | 298 | debugs(28, 3, "aclmatchAclList: " << this << " returning false (AND list entry failed to match)"); |
299 | ||
ab321f4b | 300 | bool async = state_ != NullState::Instance(); |
301 | ||
48071869 | 302 | checkForAsync(); |
501b58f9 | 303 | |
ab321f4b | 304 | bool async_in_progress = asyncInProgress(); |
bf8fe701 | 305 | debugs(28, 3, "aclmatchAclList: async=" << (async ? 1 : 0) << |
306 | " nodeMatched=" << (nodeMatched ? 1 : 0) << | |
307 | " async_in_progress=" << (async_in_progress ? 1 : 0) << | |
ff3f3722 | 308 | " lastACLResult() = " << (lastACLResult() ? 1 : 0) << |
309 | " finished() = " << finished()); | |
310 | ||
311 | if (finished()) { | |
312 | PROF_stop(aclMatchAclList); | |
313 | return; | |
314 | } | |
ab321f4b | 315 | |
316 | if (async && nodeMatched && !asyncInProgress() && lastACLResult()) { | |
317 | // async acl, but using cached response, and it was a match | |
318 | node = node->next; | |
319 | continue; | |
320 | } | |
321 | ||
62e76326 | 322 | PROF_stop(aclMatchAclList); |
501b58f9 | 323 | |
48071869 | 324 | return; |
62e76326 | 325 | } |
326 | ||
327 | node = node->next; | |
225b7b10 | 328 | } |
62e76326 | 329 | |
bf8fe701 | 330 | debugs(28, 3, "aclmatchAclList: " << this << " returning true (AND list satisfied)"); |
331 | ||
48071869 | 332 | markFinished(); |
225b7b10 | 333 | PROF_stop(aclMatchAclList); |
225b7b10 | 334 | } |
335 | ||
336 | CBDATA_CLASS_INIT(ACLChecklist); | |
337 | ||
338 | void * | |
339 | ACLChecklist::operator new (size_t size) | |
340 | { | |
341 | assert (size == sizeof(ACLChecklist)); | |
342 | CBDATA_INIT_TYPE(ACLChecklist); | |
343 | ACLChecklist *result = cbdataAlloc(ACLChecklist); | |
aa625860 | 344 | return result; |
225b7b10 | 345 | } |
62e76326 | 346 | |
225b7b10 | 347 | void |
348 | ACLChecklist::operator delete (void *address) | |
349 | { | |
350 | ACLChecklist *t = static_cast<ACLChecklist *>(address); | |
aa625860 | 351 | cbdataFree(t); |
225b7b10 | 352 | } |
353 | ||
225b7b10 | 354 | ACLChecklist::ACLChecklist() : accessList (NULL), my_port (0), request (NULL), |
62e76326 | 355 | reply (NULL), |
4f0ef8e8 | 356 | auth_user_request (NULL), |
225b7b10 | 357 | #if SQUID_SNMP |
4f0ef8e8 | 358 | snmp_community(NULL), |
225b7b10 | 359 | #endif |
4f0ef8e8 | 360 | callback (NULL), |
62e76326 | 361 | callback_data (NULL), |
362 | extacl_entry (NULL), | |
363 | conn_(NULL), | |
364 | async_(false), | |
365 | finished_(false), | |
366 | allow_(ACCESS_DENIED), | |
367 | state_(NullState::Instance()), | |
368 | destinationDomainChecked_(false), | |
ab321f4b | 369 | sourceDomainChecked_(false), |
370 | lastACLResult_(false) | |
225b7b10 | 371 | { |
62e76326 | 372 | |
ddfcbc22 | 373 | memset (&src_addr, '\0', sizeof (struct IN_ADDR)); |
62e76326 | 374 | |
ddfcbc22 | 375 | memset (&dst_addr, '\0', sizeof (struct IN_ADDR)); |
62e76326 | 376 | |
ddfcbc22 | 377 | memset (&my_addr, '\0', sizeof (struct IN_ADDR)); |
225b7b10 | 378 | rfc931[0] = '\0'; |
225b7b10 | 379 | } |
380 | ||
381 | ACLChecklist::~ACLChecklist() | |
382 | { | |
383 | assert (!asyncInProgress()); | |
62e76326 | 384 | |
225b7b10 | 385 | if (extacl_entry) |
62e76326 | 386 | cbdataReferenceDone(extacl_entry); |
387 | ||
6dd9f4bd | 388 | HTTPMSGUNLOCK(request); |
62e76326 | 389 | |
7dc5f514 | 390 | HTTPMSGUNLOCK(reply); |
391 | ||
4f0ef8e8 | 392 | /* |
393 | * DPW 2007-05-08 | |
394 | * If this fails, then we'll need a backup UNLOCK call in the | |
395 | * destructor. | |
396 | */ | |
397 | assert(auth_user_request == NULL); | |
398 | ||
a2ac85d9 | 399 | conn_ = NULL; |
62e76326 | 400 | |
225b7b10 | 401 | cbdataReferenceDone(accessList); |
62e76326 | 402 | |
bf8fe701 | 403 | debugs(28, 4, "ACLChecklist::~ACLChecklist: destroyed " << this); |
225b7b10 | 404 | } |
405 | ||
406 | ||
a2ac85d9 | 407 | ConnStateData::Pointer |
225b7b10 | 408 | ACLChecklist::conn() |
409 | { | |
410 | return conn_; | |
411 | } | |
412 | ||
413 | void | |
a2ac85d9 | 414 | ACLChecklist::conn(ConnStateData::Pointer aConn) |
225b7b10 | 415 | { |
4d3a24ca | 416 | assert (conn() == NULL); |
225b7b10 | 417 | conn_ = aConn; |
418 | } | |
419 | ||
420 | void | |
421 | ACLChecklist::AsyncState::changeState (ACLChecklist *checklist, AsyncState *newState) const | |
422 | { | |
423 | checklist->changeState(newState); | |
424 | } | |
425 | ||
426 | ACLChecklist::NullState * | |
427 | ACLChecklist::NullState::Instance() | |
428 | { | |
429 | return &_instance; | |
430 | } | |
431 | ||
432 | void | |
433 | ACLChecklist::NullState::checkForAsync(ACLChecklist *) const | |
62e76326 | 434 | {} |
225b7b10 | 435 | |
436 | ACLChecklist::NullState ACLChecklist::NullState::_instance; | |
437 | ||
438 | void | |
439 | ACLChecklist::changeState (AsyncState *newState) | |
440 | { | |
441 | /* only change from null to active and back again, | |
442 | * not active to active. | |
443 | * relax this once conversion to states is complete | |
444 | * RBC 02 2003 | |
445 | */ | |
446 | assert (state_ == NullState::Instance() || newState == NullState::Instance()); | |
447 | state_ = newState; | |
448 | } | |
449 | ||
450 | ACLChecklist::AsyncState * | |
451 | ACLChecklist::asyncState() const | |
452 | { | |
453 | return state_; | |
454 | } | |
455 | ||
456 | void | |
457 | ACLChecklist::nonBlockingCheck(PF * callback_, void *callback_data_) | |
458 | { | |
459 | callback = callback_; | |
460 | callback_data = cbdataReference(callback_data_); | |
461 | check(); | |
462 | } | |
463 | ||
b448c119 | 464 | /* Warning: do not cbdata lock this here - it |
465 | * may be static or on the stack | |
466 | */ | |
467 | int | |
468 | ACLChecklist::fastCheck() | |
469 | { | |
470 | PROF_start(aclCheckFast); | |
471 | currentAnswer(ACCESS_DENIED); | |
bf8fe701 | 472 | debugs(28, 5, "aclCheckFast: list: " << accessList); |
b448c119 | 473 | |
474 | while (accessList) { | |
c35e260d | 475 | preCheck(); |
b448c119 | 476 | matchAclListFast(accessList->aclList); |
477 | ||
478 | if (finished()) { | |
479 | PROF_stop(aclCheckFast); | |
108d65b2 | 480 | cbdataReferenceDone(accessList); |
b448c119 | 481 | return currentAnswer() == ACCESS_ALLOWED; |
482 | } | |
483 | ||
fddded8f | 484 | /* |
485 | * Reference the next access entry | |
486 | */ | |
487 | const acl_access *A = accessList; | |
488 | ||
489 | assert (A); | |
490 | ||
491 | accessList = cbdataReference(A->next); | |
492 | ||
493 | cbdataReferenceDone(A); | |
b448c119 | 494 | } |
495 | ||
bf8fe701 | 496 | debugs(28, 5, "aclCheckFast: no matches, returning: " << (currentAnswer() == ACCESS_DENIED)); |
497 | ||
b448c119 | 498 | PROF_stop(aclCheckFast); |
499 | return currentAnswer() == ACCESS_DENIED; | |
500 | } | |
501 | ||
502 | ||
3841dd46 | 503 | bool |
504 | ACLChecklist::destinationDomainChecked() const | |
505 | { | |
506 | return destinationDomainChecked_; | |
507 | } | |
508 | ||
509 | void | |
510 | ACLChecklist::markDestinationDomainChecked() | |
511 | { | |
512 | assert (!finished() && !destinationDomainChecked()); | |
513 | destinationDomainChecked_ = true; | |
514 | } | |
515 | ||
516 | bool | |
517 | ACLChecklist::sourceDomainChecked() const | |
518 | { | |
519 | return sourceDomainChecked_; | |
520 | } | |
521 | ||
522 | void | |
523 | ACLChecklist::markSourceDomainChecked() | |
524 | { | |
525 | assert (!finished() && !sourceDomainChecked()); | |
526 | sourceDomainChecked_ = true; | |
527 | } | |
b6f25d16 | 528 | |
529 | bool | |
530 | ACLChecklist::checking() const | |
531 | { | |
532 | return checking_; | |
533 | } | |
534 | ||
535 | void | |
536 | ACLChecklist::checking (bool const newValue) | |
537 | { | |
538 | checking_ = newValue; | |
539 | } | |
ef1955a5 | 540 | |
b448c119 | 541 | /* |
542 | * Any ACLChecklist created by aclChecklistCreate() must eventually be | |
543 | * freed by ACLChecklist::operator delete(). There are two common cases: | |
544 | * | |
545 | * A) Using aclCheckFast(): The caller creates the ACLChecklist using | |
546 | * aclChecklistCreate(), checks it using aclCheckFast(), and frees it | |
547 | * using aclChecklistFree(). | |
548 | * | |
549 | * B) Using aclNBCheck() and callbacks: The caller creates the | |
550 | * ACLChecklist using aclChecklistCreate(), and passes it to | |
551 | * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(), | |
552 | * which will invoke the callback function as requested by the | |
553 | * original caller of aclNBCheck(). This callback function must | |
554 | * *not* invoke aclChecklistFree(). After the callback function | |
555 | * returns, ACLChecklist::checkCallback() will free the ACLChecklist using | |
556 | * aclChecklistFree(). | |
557 | */ | |
558 | ||
559 | ACLChecklist * | |
560 | aclChecklistCreate(const acl_access * A, HttpRequest * request, const char *ident) | |
561 | { | |
562 | ACLChecklist *checklist = new ACLChecklist; | |
563 | ||
564 | if (A) | |
565 | checklist->accessList = cbdataReference(A); | |
566 | ||
567 | if (request != NULL) { | |
6dd9f4bd | 568 | checklist->request = HTTPMSGLOCK(request); |
b448c119 | 569 | checklist->src_addr = request->client_addr; |
570 | checklist->my_addr = request->my_addr; | |
571 | checklist->my_port = request->my_port; | |
572 | } | |
573 | ||
574 | #if USE_IDENT | |
575 | if (ident) | |
576 | xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ); | |
577 | ||
578 | #endif | |
579 | ||
b448c119 | 580 | return checklist; |
581 | } | |
582 | ||
ef1955a5 | 583 | #ifndef _USE_INLINE_ |
584 | #include "ACLChecklist.cci" | |
585 | #endif |