]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/SchemeConfig.cc
Maintenance: Removed most NULLs using modernize-use-nullptr (#1075)
[thirdparty/squid.git] / src / auth / SchemeConfig.cc
CommitLineData
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 32Auth::UserRequest::Pointer
dc79fed8 33Auth::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
58Auth::SchemeConfig *
59Auth::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
69Auth::SchemeConfig *
70Auth::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 79void
dc79fed8 80Auth::SchemeConfig::registerWithCacheManager(void)
62ee09ca 81{}
d4806c91
CT
82
83void
dc79fed8 84Auth::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 139bool
dc79fed8 140Auth::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
174void
dc79fed8 175Auth::SchemeConfig::done()
d4806c91
CT
176{
177 delete keyExtras;
aee3523a 178 keyExtras = nullptr;
d4806c91
CT
179 keyExtrasLine.clean();
180}
7512e3f9 181
7e851a3e
SK
182bool
183Auth::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