]>
Commit | Line | Data |
---|---|---|
f5691f9c | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
f5691f9c | 3 | * |
bbc27441 AJ |
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. | |
f5691f9c | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 29 Authenticator */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
5c112575 | 12 | #include "auth/Config.h" |
dc79fed8 | 13 | #include "auth/forward.h" |
d8d76b36 | 14 | #include "auth/Gadgets.h" |
2d2b0bb7 | 15 | #include "auth/UserRequest.h" |
d4806c91 CT |
16 | #include "cache_cf.h" |
17 | #include "ConfigParser.h" | |
675b8408 | 18 | #include "debug/Stream.h" |
7e851a3e | 19 | #include "errorpage.h" |
77b1029d | 20 | #include "format/Format.h" |
582c2af2 | 21 | #include "globals.h" |
d4806c91 | 22 | #include "Store.h" |
3616c90c | 23 | #include "wordlist.h" |
f5691f9c | 24 | |
5817ee13 | 25 | /** |
9f3d2b2e AJ |
26 | * Get an User credentials object filled out for the given Proxy- or WWW-Authenticate header. |
27 | * Any decoding which needs to be done will be done. | |
28 | * | |
29 | * It may be a cached AuthUser or a new Unauthenticated object. | |
f5691f9c | 30 | * It may also be NULL reflecting that no user could be created. |
31 | */ | |
c7baff40 | 32 | Auth::UserRequest::Pointer |
dc79fed8 | 33 | Auth::SchemeConfig::CreateAuthUser(const char *proxy_auth, AccessLogEntry::Pointer &al) |
f5691f9c | 34 | { |
aee3523a | 35 | assert(proxy_auth != nullptr); |
bf95c10a | 36 | debugs(29, 9, "header = '" << proxy_auth << "'"); |
f5691f9c | 37 | |
dc79fed8 | 38 | Auth::SchemeConfig *config = Find(proxy_auth); |
f5691f9c | 39 | |
aee3523a | 40 | if (config == nullptr || !config->active()) { |
c6cf8dee | 41 | debugs(29, (shutting_down?3:DBG_IMPORTANT), (shutting_down?"":"WARNING: ") << |
8add28cd | 42 | "Unsupported or unconfigured/inactive proxy-auth scheme, '" << proxy_auth << "'"); |
aee3523a | 43 | return nullptr; |
f5691f9c | 44 | } |
d4806c91 CT |
45 | static MemBuf rmb; |
46 | rmb.reset(); | |
47 | if (config->keyExtras) { | |
48 | // %credentials and %username, which normally included in | |
49 | // request_format, are - at this time, but that is OK | |
50 | // because user name is added to key explicitly, and we do | |
51 | // not want to store authenticated credentials at all. | |
52 | config->keyExtras->assemble(rmb, al, 0); | |
53 | } | |
f5691f9c | 54 | |
7e851a3e | 55 | return config->decode(proxy_auth, al->request, rmb.hasContent() ? rmb.content() : nullptr); |
f5691f9c | 56 | } |
57 | ||
dc79fed8 AJ |
58 | Auth::SchemeConfig * |
59 | Auth::SchemeConfig::Find(const char *proxy_auth) | |
f5691f9c | 60 | { |
5c112575 AJ |
61 | for (auto *scheme : Auth::TheConfig.schemes) { |
62 | if (strncasecmp(proxy_auth, scheme->type(), strlen(scheme->type())) == 0) | |
63 | return scheme; | |
64 | } | |
f5691f9c | 65 | |
aee3523a | 66 | return nullptr; |
f5691f9c | 67 | } |
62ee09ca | 68 | |
dc79fed8 AJ |
69 | Auth::SchemeConfig * |
70 | Auth::SchemeConfig::GetParsed(const char *proxy_auth) | |
5bfc3dbd EB |
71 | { |
72 | if (auto *cfg = Find(proxy_auth)) | |
73 | return cfg; | |
74 | fatalf("auth_schemes: required authentication method '%s' is not configured", proxy_auth); | |
75 | return nullptr; | |
76 | } | |
77 | ||
9f3d2b2e | 78 | /** Default behaviour is to expose nothing */ |
62ee09ca | 79 | void |
dc79fed8 | 80 | Auth::SchemeConfig::registerWithCacheManager(void) |
62ee09ca | 81 | {} |
d4806c91 CT |
82 | |
83 | void | |
dc79fed8 | 84 | Auth::SchemeConfig::parse(Auth::SchemeConfig * scheme, int, char *param_str) |
d4806c91 | 85 | { |
3616c90c AJ |
86 | if (strcmp(param_str, "program") == 0) { |
87 | if (authenticateProgram) | |
88 | wordlistDestroy(&authenticateProgram); | |
89 | ||
90 | parse_wordlist(&authenticateProgram); | |
91 | ||
92 | requirePathnameExists("Authentication helper program", authenticateProgram->key); | |
93 | ||
94 | } else if (strcmp(param_str, "realm") == 0) { | |
ec980001 AJ |
95 | realm.clear(); |
96 | ||
97 | char *token = ConfigParser::NextQuotedOrToEol(); | |
98 | ||
fc3f1d5c | 99 | while (token && *token && xisspace(*token)) |
ec980001 AJ |
100 | ++token; |
101 | ||
102 | if (!token || !*token) { | |
103 | debugs(29, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Missing auth_param " << scheme->type() << " realm"); | |
104 | self_destruct(); | |
105 | return; | |
106 | } | |
107 | ||
108 | realm = token; | |
109 | ||
110 | } else if (strcmp(param_str, "children") == 0) { | |
0309fc40 AJ |
111 | authenticateChildren.parseConfig(); |
112 | ||
113 | } else if (strcmp(param_str, "key_extras") == 0) { | |
d4806c91 CT |
114 | keyExtrasLine = ConfigParser::NextQuotedToken(); |
115 | Format::Format *nlf = new ::Format::Format(scheme->type()); | |
116 | if (!nlf->parse(keyExtrasLine.termedBuf())) { | |
117 | debugs(29, DBG_CRITICAL, "FATAL: Failed parsing key_extras formatting value"); | |
118 | self_destruct(); | |
119 | return; | |
120 | } | |
121 | if (keyExtras) | |
122 | delete keyExtras; | |
123 | ||
124 | keyExtras = nlf; | |
86c63190 | 125 | |
aee3523a | 126 | if (char *t = strtok(nullptr, w_space)) { |
86c63190 AJ |
127 | debugs(29, DBG_CRITICAL, "FATAL: Unexpected argument '" << t << "' after request_format specification"); |
128 | self_destruct(); | |
d4806c91 | 129 | } |
b2b09838 AJ |
130 | } else if (strcmp(param_str, "keep_alive") == 0) { |
131 | parse_onoff(&keep_alive); | |
132 | } else if (strcmp(param_str, "utf8") == 0) { | |
133 | parse_onoff(&utf8); | |
d4806c91 | 134 | } else { |
d816f28d | 135 | debugs(29, DBG_CRITICAL, "ERROR: Unrecognised " << scheme->type() << " auth scheme parameter '" << param_str << "'"); |
d4806c91 CT |
136 | } |
137 | } | |
138 | ||
3616c90c | 139 | bool |
dc79fed8 | 140 | Auth::SchemeConfig::dump(StoreEntry *entry, const char *name, Auth::SchemeConfig *scheme) const |
d4806c91 | 141 | { |
3616c90c AJ |
142 | if (!authenticateProgram) |
143 | return false; // not configured | |
144 | ||
644b0587 | 145 | const char *schemeType = scheme->type(); |
b2b09838 | 146 | |
3616c90c | 147 | wordlist *list = authenticateProgram; |
644b0587 | 148 | storeAppendPrintf(entry, "%s %s", name, schemeType); |
aee3523a | 149 | while (list != nullptr) { |
3616c90c AJ |
150 | storeAppendPrintf(entry, " %s", list->key); |
151 | list = list->next; | |
152 | } | |
153 | storeAppendPrintf(entry, "\n"); | |
154 | ||
644b0587 | 155 | storeAppendPrintf(entry, "%s %s realm " SQUIDSBUFPH "\n", name, schemeType, SQUIDSBUFPRINT(realm)); |
ec980001 | 156 | |
0309fc40 | 157 | storeAppendPrintf(entry, "%s %s children %d startup=%d idle=%d concurrency=%d\n", |
644b0587 | 158 | name, schemeType, |
0309fc40 AJ |
159 | authenticateChildren.n_max, authenticateChildren.n_startup, |
160 | authenticateChildren.n_idle, authenticateChildren.concurrency); | |
161 | ||
b2b09838 | 162 | if (keyExtrasLine.size() > 0) // default is none |
644b0587 | 163 | storeAppendPrintf(entry, "%s %s key_extras \"%s\"\n", name, schemeType, keyExtrasLine.termedBuf()); |
b2b09838 AJ |
164 | |
165 | if (!keep_alive) // default is on | |
644b0587 | 166 | storeAppendPrintf(entry, "%s %s keep_alive off\n", name, schemeType); |
b2b09838 AJ |
167 | |
168 | if (utf8) // default is off | |
644b0587 | 169 | storeAppendPrintf(entry, "%s %s utf8 on\n", name, schemeType); |
3616c90c AJ |
170 | |
171 | return true; | |
d4806c91 CT |
172 | } |
173 | ||
174 | void | |
dc79fed8 | 175 | Auth::SchemeConfig::done() |
d4806c91 CT |
176 | { |
177 | delete keyExtras; | |
aee3523a | 178 | keyExtras = nullptr; |
d4806c91 CT |
179 | keyExtrasLine.clean(); |
180 | } | |
7512e3f9 | 181 | |
7e851a3e SK |
182 | bool |
183 | Auth::SchemeConfig::isCP1251EncodingAllowed(const HttpRequest *request) | |
184 | { | |
185 | String hdr; | |
186 | ||
187 | if (!request || !request->header.getList(Http::HdrType::ACCEPT_LANGUAGE, &hdr)) | |
188 | return false; | |
189 | ||
190 | char lang[256]; | |
191 | size_t pos = 0; // current parsing position in header string | |
192 | ||
193 | while (strHdrAcptLangGetItem(hdr, lang, 256, pos)) { | |
194 | ||
195 | /* wildcard uses the configured default language */ | |
196 | if (lang[0] == '*' && lang[1] == '\0') | |
197 | return false; | |
198 | ||
199 | if ((strncmp(lang, "ru", 2) == 0 // Russian | |
200 | || strncmp(lang, "uk", 2) == 0 // Ukrainian | |
201 | || strncmp(lang, "be", 2) == 0 // Belorussian | |
202 | || strncmp(lang, "bg", 2) == 0 // Bulgarian | |
203 | || strncmp(lang, "sr", 2) == 0)) { // Serbian | |
204 | if (lang[2] == '-') { | |
205 | if (strcmp(lang + 3, "latn") == 0) // not Cyrillic | |
206 | return false; | |
207 | } else if (xisalpha(lang[2])) { | |
208 | return false; | |
209 | } | |
210 | ||
211 | return true; | |
212 | } | |
213 | } | |
214 | ||
215 | return false; | |
216 | } | |
217 |