Bug Summary

File:d/auth.c
Warning:line 337, column 33
Access out-of-bound array element (buffer overflow)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name auth.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsd -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsd -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c auth.c
1/*
2 * The contents of this file are subject to the Mozilla Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://mozilla.org/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30/*
31 * auth.c --
32 *
33 * URL level HTTP authorization support.
34 */
35
36#include "nsd.h"
37
38/*
39 * The following proc is used for simple user authorization. It
40 * could be useful for global modules (e.g., nscp).
41 */
42
43static Ns_UserAuthorizeProc *userProcPtr = NULL((void*)0);
44
45
46/*
47 *----------------------------------------------------------------------
48 *
49 * Ns_AuthorizeRequest --
50 *
51 * Check for proper HTTP authorization of a request.
52 *
53 * Results:
54 * User supplied routine is expected to return NS_OK if authorization
55 * is allowed, NS_UNAUTHORIZED if a correct username/passwd could
56 * allow authorization, NS_FORBIDDEN if no username/passwd would ever
57 * allow access, or NS_ERROR on error.
58 *
59 * Side effects:
60 * Depends on user supplied routine. "method" and "url" could be NULL in
61 * case of non-HTTP requests.
62 *
63 *----------------------------------------------------------------------
64 */
65
66Ns_ReturnCode
67Ns_AuthorizeRequest(const char *server, const char *method, const char *url,
68 const char *user, const char *passwd, const char *peer)
69{
70 Ns_ReturnCode status;
71 const NsServer *servPtr;
72
73 NS_NONNULL_ASSERT(server != NULL)((void) (0));
74 NS_NONNULL_ASSERT(method != NULL)((void) (0));
75 NS_NONNULL_ASSERT(url != NULL)((void) (0));
76
77 servPtr = NsGetServer(server);
78 if (unlikely(servPtr == NULL)(__builtin_expect((servPtr == ((void*)0)), 0)) || servPtr->request.authProc == NULL((void*)0)) {
79 status = NS_OK;
80 } else {
81 status = (*servPtr->request.authProc)(server, method, url, user, passwd, peer);
82 }
83 return status;
84}
85
86
87/*
88 *----------------------------------------------------------------------
89 *
90 * Ns_SetRequestAuthorizeProc --
91 *
92 * Set the proc to call when authorizing requests.
93 *
94 * Results:
95 * None.
96 *
97 * Side effects:
98 * None.
99 *
100 *----------------------------------------------------------------------
101 */
102
103void
104Ns_SetRequestAuthorizeProc(const char *server, Ns_RequestAuthorizeProc *procPtr)
105{
106 NsServer *servPtr;
107
108 NS_NONNULL_ASSERT(server != NULL)((void) (0));
109 NS_NONNULL_ASSERT(procPtr != NULL)((void) (0));
110
111 servPtr = NsGetServer(server);
112 if (servPtr != NULL((void*)0)) {
113 servPtr->request.authProc = procPtr;
114 }
115}
116
117
118/*
119 *----------------------------------------------------------------------
120 *
121 * NsTclRequestAuthorizeObjCmd --
122 *
123 * Implements "ns_requestauthorize".
124 *
125 * Results:
126 * Tcl result.
127 *
128 * Side effects:
129 * See docs.
130 *
131 *----------------------------------------------------------------------
132 */
133
134int
135NsTclRequestAuthorizeObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
136{
137 const NsInterp *itPtr = clientData;
138 int result = TCL_OK0;
139 char *method, *url, *authuser, *authpasswd, *ipaddr = NULL((void*)0);
140 Ns_ObjvSpec args[] = {
141 {"method", Ns_ObjvString, &method, NULL((void*)0)},
142 {"url", Ns_ObjvString, &url, NULL((void*)0)},
143 {"authuser", Ns_ObjvString, &authuser, NULL((void*)0)},
144 {"authpasswd", Ns_ObjvString, &authpasswd, NULL((void*)0)},
145 {"?ipaddr", Ns_ObjvString, &ipaddr, NULL((void*)0)},
146 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
147 };
148
149 if (Ns_ParseObjv(NULL((void*)0), args, interp, 1, objc, objv) != NS_OK) {
150 result = TCL_ERROR1;
151
152 } else {
153 Ns_ReturnCode status;
154
155 status = Ns_AuthorizeRequest(itPtr->servPtr->server, method, url,
156 authuser, authpasswd, ipaddr);
157 switch (status) {
158 case NS_OK:
159 Tcl_SetObjResult(interp, Tcl_NewStringObj("OK", 2));
160 break;
161
162 case NS_ERROR:
163 Tcl_SetObjResult(interp, Tcl_NewStringObj("ERROR", 5));
164 break;
165
166 case NS_FORBIDDEN:
167 Tcl_SetObjResult(interp, Tcl_NewStringObj("FORBIDDEN", -1));
168 break;
169
170 case NS_UNAUTHORIZED:
171 Tcl_SetObjResult(interp, Tcl_NewStringObj("UNAUTHORIZED", -1));
172 break;
173
174 case NS_FILTER_BREAK: NS_FALL_THROUGH((void)0); /* fall through */
175 case NS_FILTER_RETURN: NS_FALL_THROUGH((void)0); /* fall through */
176 case NS_TIMEOUT:
177 Ns_TclPrintfResult(interp, "could not authorize \"%s %s\"",
178 Tcl_GetString(objv[1]), Tcl_GetString(objv[2]));
179 result = TCL_ERROR1;
180 }
181 }
182 return result;
183}
184
185
186/*
187 *----------------------------------------------------------------------
188 *
189 * Ns_AuthorizeUser --
190 *
191 * Verify that a user's password matches his name.
192 * passwd is the unencrypted password.
193 *
194 * Results:
195 * NS_OK or NS_ERROR; if none registered, NS_ERROR.
196 *
197 * Side effects:
198 * Depends on the supplied routine.
199 *
200 *----------------------------------------------------------------------
201 */
202
203Ns_ReturnCode
204Ns_AuthorizeUser(const char *user, const char *passwd)
205{
206 Ns_ReturnCode status;
207
208 NS_NONNULL_ASSERT(user != NULL)((void) (0));
209 NS_NONNULL_ASSERT(passwd != NULL)((void) (0));
210
211 if (userProcPtr == NULL((void*)0)) {
212 status = NS_ERROR;
213 } else {
214 status = (*userProcPtr)(user, passwd);
215 }
216 return status;
217}
218
219
220/*
221 *----------------------------------------------------------------------
222 *
223 * Ns_SetUserAuthorizeProc --
224 *
225 * Set the proc to call when authorizing users.
226 *
227 * Results:
228 * None.
229 *
230 * Side effects:
231 * None.
232 *
233 *----------------------------------------------------------------------
234 */
235
236void
237Ns_SetUserAuthorizeProc(Ns_UserAuthorizeProc *procPtr)
238{
239 NS_NONNULL_ASSERT(procPtr != NULL)((void) (0));
240
241 userProcPtr = procPtr;
242}
243
244/*
245 *----------------------------------------------------------------------
246 *
247 * NsParseAuth --
248 *
249 * Parse an HTTP authorization string.
250 *
251 * Results:
252 * None.
253 *
254 * Side effects:
255 * May set the auth Passwd and User connection pointers.
256 *
257 *----------------------------------------------------------------------
258 */
259
260void
261NsParseAuth(Conn *connPtr, const char *auth)
262{
263 register char *p;
264 Tcl_DString authDs;
265
266 NS_NONNULL_ASSERT(connPtr != NULL)((void) (0));
267 NS_NONNULL_ASSERT(auth != NULL)((void) (0));
268
269 if (connPtr->auth == NULL((void*)0)) {
1
Assuming field 'auth' is not equal to NULL
2
Taking false branch
270 connPtr->auth = Ns_SetCreate(NS_SET_NAME_AUTH"auth");
271 }
272
273 Tcl_DStringInit(&authDs);
274 Tcl_DStringAppend(&authDs, auth, -1);
275
276 p = authDs.string;
277 while (*p != '\0' && CHARTYPE(space, *p)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*p))))] &
(unsigned short int) _ISspace))
== 0) {
3
Assuming the condition is true
4
Loop condition is false. Execution continues on line 280
278 ++p;
279 }
280 if (*p != '\0') {
5
Taking true branch
281 register char *q, *v;
282 char save;
283
284 save = *p;
285 *p = '\0';
286
287 if (STRIEQ(authDs.string, "Basic")(strcasecmp((authDs.string),("Basic")) == 0)) {
6
Assuming the condition is false
7
Taking false branch
288 size_t size;
289 ssize_t userLength;
290
291 (void)Ns_SetPutSz(connPtr->auth, "AuthMethod", 10, "Basic", 5);
292
293 /* Skip spaces */
294 q = p + 1;
295 while (*q != '\0' && CHARTYPE(space, *q)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*q))))] &
(unsigned short int) _ISspace))
!= 0) {
296 q++;
297 }
298
299 size = strlen(q) + 3u;
300 v = ns_malloc(size);
301 size = Ns_HtuuDecode(q, (unsigned char *) v, size);
302 v[size] = '\0';
303
304 q = strchr(v, INTCHAR(':')((int)((unsigned char)((':')))));
305 if (q != NULL((void*)0)) {
306 ssize_t pwLength;
307
308 *q++ = '\0';
309 pwLength = ((v+size) - q);
310 (void)Ns_SetPutSz(connPtr->auth, "Password", 8, q, pwLength);
311 userLength = (ssize_t)size - (pwLength + 1);
312 } else {
313 userLength = (ssize_t)size;
314 }
315 (void)Ns_SetPutSz(connPtr->auth, "Username", 8, v, userLength);
316 ns_free(v);
317
318 } else if (STRIEQ(authDs.string, "Digest")(strcasecmp((authDs.string),("Digest")) == 0)) {
8
Taking true branch
319 (void)Ns_SetPutSz(connPtr->auth, "AuthMethod", 10, "Digest", 6);
320
321 /* Skip spaces */
322 q = p + 1;
323 while (*q != '\0' && CHARTYPE(space, *q)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*q))))] &
(unsigned short int) _ISspace))
!= 0) {
9
Assuming the condition is true
10
Loop condition is false. Execution continues on line 327
324 q++;
325 }
326
327 while (*q != '\0') {
11
Loop condition is true. Entering loop body
328 size_t idx;
329 char save2;
330
331 p = strchr(q, INTCHAR('=')((int)((unsigned char)(('=')))));
332 if (p == NULL((void*)0)) {
12
Assuming 'p' is not equal to NULL
13
Taking false branch
333 break;
334 }
335 v = p - 1;
336 /* Trim trailing spaces */
337 while (v > q && CHARTYPE(space, *v)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*v))))] &
(unsigned short int) _ISspace))
!= 0) {
14
Assuming 'v' is > 'q'
15
Access out-of-bound array element (buffer overflow)
338 v--;
339 }
340 /* Remember position */
341 save2 = *(++v);
342 *v = '\0';
343 idx = Ns_SetPutSz(connPtr->auth, q, (ssize_t)(v-q), NULL((void*)0), 0);
344 /* Restore character */
345 *v = save2;
346 /* Skip = and optional spaces */
347 p++;
348 while (*p != '\0' && CHARTYPE(space, *p)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*p))))] &
(unsigned short int) _ISspace))
!= 0) {
349 p++;
350 }
351 if (*p == '\0') {
352 break;
353 }
354 /* Find end of the value, deal with quotes strings */
355 if (*p == '"') {
356 for (q = ++p; *q != '\0' && *q != '"'; q++) {
357 ;
358 }
359 } else {
360 for (q = p; *q != '\0' && *q != ',' && CHARTYPE(space, *q)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*q))))] &
(unsigned short int) _ISspace))
== 0; q++) {
361 ;
362 }
363 }
364 save2 = *q;
365 *q = '\0';
366 /* Update with current value */
367 Ns_SetPutValueSz(connPtr->auth, idx, p, -1);
368 *q = save2;
369 /* Advance to the end of the param value, can be end or next name*/
370 while (*q != '\0' && (*q == ',' || *q == '"' || CHARTYPE(space, *q)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*q))))] &
(unsigned short int) _ISspace))
!= 0)) {
371 q++;
372 }
373 }
374 } else if (STRIEQ(authDs.string, "Bearer")(strcasecmp((authDs.string),("Bearer")) == 0)) {
375
376 (void)Ns_SetPutSz(connPtr->auth, "AuthMethod", 10, "Bearer", 6);
377
378 /* Skip spaces */
379 q = p + 1;
380 while (*q != '\0' && CHARTYPE(space, *q)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*q))))] &
(unsigned short int) _ISspace))
!= 0) {
381 q++;
382 }
383 (void)Ns_SetPutSz(connPtr->auth, "Token", 5, q, authDs.length - (q - authDs.string));
384 }
385 if (p != NULL((void*)0)) {
386 *p = save;
387 }
388 }
389 Tcl_DStringFree(&authDs);
390}
391
392/*
393 * Local Variables:
394 * mode: c
395 * c-basic-offset: 4
396 * fill-column: 78
397 * indent-tabs-mode: nil
398 * End:
399 */