]> git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/SchemeConfig.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / auth / SchemeConfig.cc
1 /*
2 * Copyright (C) 1996-2020 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 "auth/Config.h"
13 #include "auth/forward.h"
14 #include "auth/Gadgets.h"
15 #include "auth/UserRequest.h"
16 #include "cache_cf.h"
17 #include "ConfigParser.h"
18 #include "Debug.h"
19 #include "errorpage.h"
20 #include "format/Format.h"
21 #include "globals.h"
22 #include "Store.h"
23 #include "wordlist.h"
24
25 /**
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.
30 * It may also be NULL reflecting that no user could be created.
31 */
32 Auth::UserRequest::Pointer
33 Auth::SchemeConfig::CreateAuthUser(const char *proxy_auth, AccessLogEntry::Pointer &al)
34 {
35 assert(proxy_auth != NULL);
36 debugs(29, 9, HERE << "header = '" << proxy_auth << "'");
37
38 Auth::SchemeConfig *config = Find(proxy_auth);
39
40 if (config == NULL || !config->active()) {
41 debugs(29, (shutting_down?3:DBG_IMPORTANT), (shutting_down?"":"WARNING: ") <<
42 "Unsupported or unconfigured/inactive proxy-auth scheme, '" << proxy_auth << "'");
43 return NULL;
44 }
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 }
54
55 return config->decode(proxy_auth, al->request, rmb.hasContent() ? rmb.content() : nullptr);
56 }
57
58 Auth::SchemeConfig *
59 Auth::SchemeConfig::Find(const char *proxy_auth)
60 {
61 for (auto *scheme : Auth::TheConfig.schemes) {
62 if (strncasecmp(proxy_auth, scheme->type(), strlen(scheme->type())) == 0)
63 return scheme;
64 }
65
66 return NULL;
67 }
68
69 Auth::SchemeConfig *
70 Auth::SchemeConfig::GetParsed(const char *proxy_auth)
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
78 /** Default behaviour is to expose nothing */
79 void
80 Auth::SchemeConfig::registerWithCacheManager(void)
81 {}
82
83 void
84 Auth::SchemeConfig::parse(Auth::SchemeConfig * scheme, int, char *param_str)
85 {
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) {
95 realm.clear();
96
97 char *token = ConfigParser::NextQuotedOrToEol();
98
99 while (token && *token && xisspace(*token))
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) {
111 authenticateChildren.parseConfig();
112
113 } else if (strcmp(param_str, "key_extras") == 0) {
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;
125
126 if (char *t = strtok(NULL, w_space)) {
127 debugs(29, DBG_CRITICAL, "FATAL: Unexpected argument '" << t << "' after request_format specification");
128 self_destruct();
129 }
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);
134 } else {
135 debugs(29, DBG_CRITICAL, "Unrecognised " << scheme->type() << " auth scheme parameter '" << param_str << "'");
136 }
137 }
138
139 bool
140 Auth::SchemeConfig::dump(StoreEntry *entry, const char *name, Auth::SchemeConfig *scheme) const
141 {
142 if (!authenticateProgram)
143 return false; // not configured
144
145 const char *schemeType = scheme->type();
146
147 wordlist *list = authenticateProgram;
148 storeAppendPrintf(entry, "%s %s", name, schemeType);
149 while (list != NULL) {
150 storeAppendPrintf(entry, " %s", list->key);
151 list = list->next;
152 }
153 storeAppendPrintf(entry, "\n");
154
155 storeAppendPrintf(entry, "%s %s realm " SQUIDSBUFPH "\n", name, schemeType, SQUIDSBUFPRINT(realm));
156
157 storeAppendPrintf(entry, "%s %s children %d startup=%d idle=%d concurrency=%d\n",
158 name, schemeType,
159 authenticateChildren.n_max, authenticateChildren.n_startup,
160 authenticateChildren.n_idle, authenticateChildren.concurrency);
161
162 if (keyExtrasLine.size() > 0) // default is none
163 storeAppendPrintf(entry, "%s %s key_extras \"%s\"\n", name, schemeType, keyExtrasLine.termedBuf());
164
165 if (!keep_alive) // default is on
166 storeAppendPrintf(entry, "%s %s keep_alive off\n", name, schemeType);
167
168 if (utf8) // default is off
169 storeAppendPrintf(entry, "%s %s utf8 on\n", name, schemeType);
170
171 return true;
172 }
173
174 void
175 Auth::SchemeConfig::done()
176 {
177 delete keyExtras;
178 keyExtras = NULL;
179 keyExtrasLine.clean();
180 }
181
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