Bug Summary

File:d/cookies.c
Warning:line 669, column 9
Duplicate code detected
Note:line 851, column 9
Similar code here

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 cookies.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 cookies.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 * cookies.c --
32 *
33 * Routines to manipulate HTTP cookie headers.
34 *
35 */
36
37#include "nsd.h"
38
39/*
40 * Local functions defined in this file.
41 */
42
43static int GetFirstNamedCookie(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs,
44 const char *setName, const char *name)
45 NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))) NS_GNUC_NONNULL(4)__attribute__((__nonnull__(4)));
46
47static int GetAllNamedCookies(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs,
48 const char *setName, const char *name)
49 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3))) NS_GNUC_NONNULL(4)__attribute__((__nonnull__(4)));
50
51static bool_Bool DeleteNamedCookies(Ns_Set *hdrs, const char *setName,
52 const char *name)
53 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3)));
54
55
56typedef char* (CookieParser)(Ns_DStringTcl_DString *dest, char *chars, const char *name,
57 size_t nameLen, char **nextPtr)
58 NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3)));
59
60static CookieParser GetFromCookieHeader;
61static CookieParser GetFromSetCookieHeader;
62
63static char *CopyCookieValue(Tcl_DString *dest, char *valueStart)
64 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
65
66static Ns_ObjvTable samesiteValues[] = {
67 {"strict", UCHAR('s')((unsigned char)('s'))},
68 {"lax", UCHAR('l')((unsigned char)('l'))},
69 {"none", UCHAR('n')((unsigned char)('n'))},
70 {NULL((void*)0), 0u}
71};
72
73
74
75/*
76 *----------------------------------------------------------------------
77 *
78 * CopyCookieValue --
79 *
80 * Copy the CookieValue into the provided Tcl_DString
81 *
82 * Results:
83 * None
84 *
85 * Side effects:
86 * Append to provided Tcl_DString
87 *
88 *----------------------------------------------------------------------
89 */
90
91static char *
92CopyCookieValue(Tcl_DString *dest, char *valueStart)
93{
94 char save, *q;
95
96 NS_NONNULL_ASSERT(dest != NULL)((void) (0));
97 NS_NONNULL_ASSERT(valueStart != NULL)((void) (0));
98
99 if (*valueStart == '"') {
100 /*
101 * Advance past optional quote.
102 */
103 ++valueStart;
104 }
105 q = valueStart;
106 while (*q != '"' && *q != ';' && *q != '\0') {
107 ++q;
108 }
109 save = *q;
110 *q = '\0';
111 Ns_CookieDecode(dest, valueStart, NULL((void*)0));
112 *q = save;
113
114 /*
115 * Advance past delimiter.
116 */
117 while (*q == '"' || *q == ';') {
118 q++;
119 }
120
121 return q;
122}
123
124
125/*
126 *----------------------------------------------------------------------
127 *
128 * GetFromCookieHeader --
129 *
130 * Get a cookie from the cookie header. The cookie header field has a
131 * content of the form:
132 *
133 * cookie1="value1"; cookie2="value2"; style=null; ...
134 *
135 * so we have to iterate over the cookie/value pairs separated with
136 * semicolons.
137 *
138 * Results:
139 * On success a non-null value pointing the begin of the found
140 * cookie such we can iterate to search for more cookies with the same
141 * name
142 *
143 * Side effects:
144 * When Tcl_DString dest is provided, the value of the cookie is
145 * appended to the DString.
146 *
147 *----------------------------------------------------------------------
148 */
149
150static char *
151GetFromCookieHeader(Ns_DStringTcl_DString *dest, char *chars, const char *name,
152 size_t nameLen, char **nextPtr)
153{
154 char *cookieStart = NULL((void*)0), *toParse = chars;
155
156 NS_NONNULL_ASSERT(chars != NULL)((void) (0));
157 NS_NONNULL_ASSERT(name != NULL)((void) (0));
158
159 for ( ; likely(*toParse != '\0')(__builtin_expect((*toParse != '\0'), 1)); ) {
160 /*
161 * Skip optional white space.
162 */
163 for (; (CHARTYPE(space, *toParse)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*toParse)
)))] & (unsigned short int) _ISspace))
!= 0); toParse++) {
164 }
165 if (*toParse == '\0') {
166 break;
167 }
168
169 if (strncmp(toParse, name, nameLen) == 0) {
170 char *q = toParse + nameLen;
171
172 /*
173 * Name starts correctly
174 */
175 if (likely(*q == '=')(__builtin_expect((*q == '='), 1))) {
176 /*
177 * Full match, we found the cookie
178 */
179 cookieStart = toParse;
180 q++; /* advance past equals sign */
181 if (dest != NULL((void*)0)) {
182 q = CopyCookieValue(dest, q);
183 }
184 toParse = q;
185 break;
186 }
187 }
188 /*
189 * Look for the next semicolon
190 */
191 for (; (*toParse != '\0') && (*toParse != ';'); toParse++) {
192 ;
193 }
194 if (*toParse == ';') {
195 /*
196 * We found a semicolon and skip it;
197 */
198 toParse++;
199 }
200 }
201
202 if (nextPtr != NULL((void*)0)) {
203 *nextPtr = toParse;
204 }
205
206 return cookieStart;
207}
208
209
210/*
211 *----------------------------------------------------------------------
212 *
213 * GetFromSetCookieHeader --
214 *
215 * Get a cookie from the set-cookie header. The set-cookie header field
216 * has a content of the form:
217 *
218 * cookie1="new-value"; Expires=Fri, 01-Jan-2035 01:00:00 GMT; Path=/; HttpOnly
219 *
220 * In order to get the cookie-value, the entry has to start with a
221 * name/value pair.
222 *
223 * Results:
224 * On success a non-null value pointing the begin of the found
225 * cookie
226 *
227 * Side effects:
228 * When Tcl_DString dest is provided, the value of the cookie is
229 * appended to the DString.
230 *
231 *----------------------------------------------------------------------
232 */
233
234static char *
235GetFromSetCookieHeader(Ns_DStringTcl_DString *dest, char *chars, const char *name,
236 size_t nameLen, char **nextPtr) {
237 char *cookieStart = NULL((void*)0), *toParse = chars;
238
239 NS_NONNULL_ASSERT(chars != NULL)((void) (0));
240 NS_NONNULL_ASSERT(name != NULL)((void) (0));
241
242 /*
243 * Skip white space (should not be needed).
244 */
245 for (; (CHARTYPE(space, *toParse)(((*__ctype_b_loc ())[(int) (((int)((unsigned char)(*toParse)
)))] & (unsigned short int) _ISspace))
!= 0); toParse++) {
246 ;
247 }
248 if (strncmp(toParse, name, nameLen) == 0) {
249 char *q = toParse + nameLen;
250
251 /*
252 * Name starts correctly
253 */
254
255 if (*q == '=') {
256 /*
257 * Full match, we found the cookie
258 */
259 cookieStart = toParse;
260 q++; /* advance past equals sign */
261 if (dest != NULL((void*)0)) {
262 q = CopyCookieValue(dest, q);
263 }
264 toParse = q;
265 }
266 }
267 if (nextPtr != NULL((void*)0)) {
268 *nextPtr = toParse;
269 }
270
271 return cookieStart;
272}
273
274
275/*
276 *----------------------------------------------------------------------
277 *
278 * GetFirstNamedCookie --
279 *
280 * Search for a cookie with the given name in the given set and
281 * return the first hit.
282 *
283 * Results:
284 * index value on success, or -1
285 *
286 * Side effects:
287 * when NsString dest is provided, the value of the cookie is
288 * appended to the DString.
289 *
290 *----------------------------------------------------------------------
291 */
292
293static int
294GetFirstNamedCookie(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, const char *setName,
295 const char *name)
296{
297 int idx = -1;
298 size_t nameLen, i;
299 CookieParser *cookieParser;
300
301 NS_NONNULL_ASSERT(hdrs != NULL)((void) (0));
302 NS_NONNULL_ASSERT(setName != NULL)((void) (0));
303 NS_NONNULL_ASSERT(name != NULL)((void) (0));
304
305 nameLen = strlen(name);
306
307 cookieParser = (*setName == 'c')
308 ? GetFromCookieHeader
309 : GetFromSetCookieHeader;
310
311 for (i = 0u; i < hdrs->size; ++i) {
312 if (strcasecmp(hdrs->fields[i].name, setName) == 0) {
313 /*
314 * We have the right header.
315 */
316 if ((*cookieParser)(dest, hdrs->fields[i].value, name,
317 nameLen, NULL((void*)0)) != NULL((void*)0)) {
318 /*
319 * We found the result.
320 */
321 idx = (int) i;
322 break;
323 }
324 }
325 }
326
327 return idx;
328}
329
330/*
331 *----------------------------------------------------------------------
332 *
333 * GetAllNamedCookies --
334 *
335 * Search for a cookie with the given name in the given set and
336 * return all hits.
337 *
338 * Results:
339 * Number of cookies with the given name
340 *
341 * Side effects:
342 * Update the first argument with a list of cookie values
343 *
344 *----------------------------------------------------------------------
345 */
346static int
347GetAllNamedCookies(Ns_DStringTcl_DString *dest, const Ns_Set *hdrs, const char *setName,
348 const char *name)
349{
350 int count = 0;
351 size_t nameLen, i;
352 CookieParser *cookieParser;
353
354 NS_NONNULL_ASSERT(dest != NULL)((void) (0));
355 NS_NONNULL_ASSERT(hdrs != NULL)((void) (0));
356 NS_NONNULL_ASSERT(setName != NULL)((void) (0));
357 NS_NONNULL_ASSERT(name != NULL)((void) (0));
358
359 nameLen = strlen(name);
360 cookieParser = (*setName == 'c')
361 ? GetFromCookieHeader
362 : GetFromSetCookieHeader;
363
364 for (i = 0u; i < hdrs->size; i++) {
365 if (strcasecmp(hdrs->fields[i].name, setName) == 0) {
366 char *toParse;
367
368 /*
369 * We have the right header, parse the string;
370 */
371 for (toParse = hdrs->fields[i].value; *toParse != '\0'; ) {
372 Ns_DStringTcl_DString cookie;
373
374 Ns_DStringInitTcl_DStringInit(&cookie);
375 if ((*cookieParser)(&cookie, toParse, name, nameLen,
376 &toParse) != NULL((void*)0)) {
377 /*
378 * We found the named cookie;
379 */
380 count ++;
381 Tcl_DStringAppendElement(dest, cookie.string);
382 }
383 Ns_DStringFreeTcl_DStringFree(&cookie);
384 }
385 break;
386 }
387 }
388
389 return count;
390}
391
392
393/*
394 *----------------------------------------------------------------------
395 *
396 * DeleteNamedCookies --
397 *
398 * Delete all cookies with the specified name form the given set.
399 *
400 * Results:
401 * Boolean value.
402 *
403 * Side effects:
404 * Delete nsset entry.
405 *
406 *----------------------------------------------------------------------
407 */
408
409static bool_Bool
410DeleteNamedCookies(Ns_Set *hdrs, const char *setName, const char *name)
411{
412 bool_Bool success = NS_FALSE0;
413
414 NS_NONNULL_ASSERT(hdrs != NULL)((void) (0));
415 NS_NONNULL_ASSERT(setName != NULL)((void) (0));
416 NS_NONNULL_ASSERT(name != NULL)((void) (0));
417
418 for (;;) {
419 int idx = GetFirstNamedCookie(NULL((void*)0), hdrs, setName, name);
420 if (idx != -1) {
421 Ns_SetDelete(hdrs, idx);
422 success = NS_TRUE1;
423 } else {
424 break;
425 }
426 }
427 return success;
428}
429
430
431/*
432 *----------------------------------------------------------------------
433 *
434 * Ns_ConnSetCookie, Ns_ConnSetCookieEx, Ns_ConnSetSecureCookie --
435 *
436 * Set a cookie for the given connection.
437 *
438 * Results:
439 * None.
440 *
441 * Side effects:
442 * Existing cookie with same name, path, domain will be dropped
443 * by client.
444 *
445 *----------------------------------------------------------------------
446 */
447
448void
449Ns_ConnSetCookieEx(const Ns_Conn *conn, const char *name, const char *value,
450 time_t maxage, const char *domain, const char *path,
451 unsigned int flags)
452{
453 Ns_DStringTcl_DString cookie;
454
455 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
456 NS_NONNULL_ASSERT(name != NULL)((void) (0));
457
458 if ((flags & NS_COOKIE_REPLACE0x08u) != 0u) {
459 (void)DeleteNamedCookies(Ns_ConnOutputHeaders(conn), "set-cookie",
460 name);
461 }
462
463 Ns_DStringInitTcl_DStringInit(&cookie);
464 Ns_DStringVarAppend(&cookie, name, "=\"", (char *)0L);
465 if (value != NULL((void*)0)) {
466 Ns_CookieEncode(&cookie, value, NULL((void*)0));
467 }
468 Ns_DStringAppend(&cookie, "\"")Tcl_DStringAppend((&cookie), ("\""), -1);
469 if ((flags & NS_COOKIE_EXPIRENOW0x10u) != 0u) {
470 Ns_DStringAppend(&cookie, "; Expires=Fri, 01-Jan-1980 01:00:00 GMT")Tcl_DStringAppend((&cookie), ("; Expires=Fri, 01-Jan-1980 01:00:00 GMT"
), -1)
;
471 } else if (maxage == TIME_T_MAX9223372036854775807L) {
472 Ns_DStringAppend(&cookie, "; Expires=Fri, 01-Jan-2035 01:00:00 GMT")Tcl_DStringAppend((&cookie), ("; Expires=Fri, 01-Jan-2035 01:00:00 GMT"
), -1)
;
473 } else if (maxage > 0) {
474 Ns_DStringPrintf(&cookie, "; Max-Age=%" PRId64"l" "d", (int64_t)maxage);
475 } else {
476 /*
477 * maxage == 0, don't specify any expiry
478 */
479 }
480 /* ignore empty domain, since IE rejects it */
481 if (domain != NULL((void*)0) && *domain != '\0') {
482 Ns_DStringVarAppend(&cookie, "; Domain=", domain, (char *)0L);
483 }
484 if (path != NULL((void*)0)) {
485 Ns_DStringVarAppend(&cookie, "; Path=", path, (char *)0L);
486 }
487 if ((flags & NS_COOKIE_SECURE0x01u) != 0u) {
488 Ns_DStringAppend(&cookie, "; Secure")Tcl_DStringAppend((&cookie), ("; Secure"), -1);
489 }
490 if ((flags & NS_COOKIE_DISCARD0x04u) != 0u) {
491 Ns_DStringAppend(&cookie, "; Discard")Tcl_DStringAppend((&cookie), ("; Discard"), -1);
492 }
493 if ((flags & NS_COOKIE_SCRIPTABLE0x02u) == 0u) {
494 Ns_DStringAppend(&cookie, "; HttpOnly")Tcl_DStringAppend((&cookie), ("; HttpOnly"), -1);
495 }
496
497 if ((flags & NS_COOKIE_SAMESITE_STRICT0x20u) != 0u) {
498 Ns_DStringAppend(&cookie, "; SameSite=Strict")Tcl_DStringAppend((&cookie), ("; SameSite=Strict"), -1);
499 } else if ((flags & NS_COOKIE_SAMESITE_LAX0x40u) != 0u) {
500 Ns_DStringAppend(&cookie, "; SameSite=Lax")Tcl_DStringAppend((&cookie), ("; SameSite=Lax"), -1);
501 } else if ((flags & NS_COOKIE_SAMESITE_NONE0x80u) != 0u) {
502 Ns_DStringAppend(&cookie, "; SameSite=None")Tcl_DStringAppend((&cookie), ("; SameSite=None"), -1);
503 }
504
505
506 Ns_ConnSetHeaders(conn, "Set-Cookie", cookie.string);
507 Ns_DStringFreeTcl_DStringFree(&cookie);
508}
509
510void
511Ns_ConnSetCookie(const Ns_Conn *conn, const char *name, const char *value,
512 time_t maxage)
513{
514 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
515 NS_NONNULL_ASSERT(name != NULL)((void) (0));
516
517 Ns_ConnSetCookieEx(conn, name, value, maxage, NULL((void*)0), NULL((void*)0), 0u);
518}
519
520void
521Ns_ConnSetSecureCookie(const Ns_Conn *conn, const char *name, const char *value,
522 time_t maxage)
523{
524 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
525 NS_NONNULL_ASSERT(name != NULL)((void) (0));
526
527 Ns_ConnSetCookieEx(conn, name, value, maxage, NULL((void*)0), NULL((void*)0), NS_COOKIE_SECURE0x01u);
528}
529
530
531/*
532 *----------------------------------------------------------------------
533 *
534 * Ns_ConnDeleteCookie, Ns_ConnDeleteSecureCookie --
535 *
536 * Expire immediately the cookie with matching name, domain and path.
537 *
538 * Results:
539 * None.
540 *
541 * Side effects:
542 * None.
543 *
544 *----------------------------------------------------------------------
545 */
546
547void
548Ns_ConnDeleteCookie(const Ns_Conn *conn, const char *name, const char *domain,
549 const char *path)
550{
551 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
552 NS_NONNULL_ASSERT(name != NULL)((void) (0));
553
554 Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path,
555 NS_COOKIE_EXPIRENOW0x10u);
556}
557
558void
559Ns_ConnDeleteSecureCookie(const Ns_Conn *conn, const char *name,
560 const char *domain, const char *path)
561{
562 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
563 NS_NONNULL_ASSERT(name != NULL)((void) (0));
564
565 Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path,
566 NS_COOKIE_EXPIRENOW0x10u|NS_COOKIE_SECURE0x01u);
567}
568
569
570/*
571 *----------------------------------------------------------------------
572 *
573 * Ns_ConnGetCookie --
574 *
575 * Get first matching cookie for the given connection.
576 *
577 * Results:
578 * dest->string or NULL on error.
579 *
580 * Side effects:
581 * Cookie value is CookieDecoded before placement in dest.
582 *
583 *----------------------------------------------------------------------
584 */
585
586const char *
587Ns_ConnGetCookie(Ns_DStringTcl_DString *dest, const Ns_Conn *conn, const char *name)
588{
589 int idx;
590
591 NS_NONNULL_ASSERT(dest != NULL)((void) (0));
592 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
593 NS_NONNULL_ASSERT(name != NULL)((void) (0));
594
595 idx = GetFirstNamedCookie(dest, Ns_ConnHeaders(conn), "cookie", name);
596
597 return idx != -1 ? Ns_DStringValue(dest)((dest)->string) : NULL((void*)0);
598}
599
600
601
602/*
603 *----------------------------------------------------------------------
604 *
605 * NsTclSetCookieObjCmd --
606 *
607 * Implements "ns_setcookie".
608 *
609 * Results:
610 * Tcl result.
611 *
612 * Side effects:
613 * None.
614 *
615 *----------------------------------------------------------------------
616 */
617
618int
619NsTclSetCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp,
620 int objc, Tcl_Obj *const* objv)
621{
622 Ns_Conn *conn;
623 char *name, *data, *domain = NULL((void*)0), *path = NULL((void*)0);
624 int secure = 0, scriptable = 0, discard = 0, replace = 0, result;
625 int samesite = INTCHAR('l')((int)((unsigned char)(('l'))));
626 Ns_Time *expiresPtr = NULL((void*)0);
627 Ns_ObjvSpec opts[] = {
628 {"-discard", Ns_ObjvBool, &discard, NULL((void*)0)},
629 {"-domain", Ns_ObjvString, &domain, NULL((void*)0)},
630 {"-expires", Ns_ObjvTime, &expiresPtr, NULL((void*)0)},
631 {"-path", Ns_ObjvString, &path, NULL((void*)0)},
632 {"-replace", Ns_ObjvBool, &replace, NULL((void*)0)},
633 {"-samesite", Ns_ObjvIndex, &samesite, samesiteValues},
634 {"-scriptable", Ns_ObjvBool, &scriptable, NULL((void*)0)},
635 {"-secure", Ns_ObjvBool, &secure, NULL((void*)0)},
636 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
637 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
638 };
639 Ns_ObjvSpec args[] = {
640 {"name", Ns_ObjvString, &name, NULL((void*)0)},
641 {"data", Ns_ObjvString, &data, NULL((void*)0)},
642 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
643 };
644
645 if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK
646 || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) {
647 result = TCL_ERROR1;
648
649 } else {
650 unsigned int flags = 0u;
651 time_t maxage;
652
653 if (secure != 0) {
654 flags |= NS_COOKIE_SECURE0x01u;
655 }
656 if (scriptable != 0) {
657 flags |= NS_COOKIE_SCRIPTABLE0x02u;
658 }
659 if (discard != 0) {
660 flags |= NS_COOKIE_DISCARD0x04u;
661 }
662 if (replace != 0) {
663 flags |= NS_COOKIE_REPLACE0x08u;
664 }
665 /*
666 * If "-samesite none" flag was provided, and secure was not set, fall
667 * back to "-samesite lax" and complain.
668 */
669 if (samesite == INTCHAR('n')((int)((unsigned char)(('n')))) && secure == 0) {
Duplicate code detected
670 Ns_Log(Warning, "cookie '%s': trying to set '-samesite none' "
671 "without the '-secure' flag. Fall back to -samesite lax", name);
672 samesite = INTCHAR('l')((int)((unsigned char)(('l'))));
673 }
674 if (samesite == INTCHAR('s')((int)((unsigned char)(('s'))))) {
675 flags |= NS_COOKIE_SAMESITE_STRICT0x20u;
676 } else if (samesite == INTCHAR('l')((int)((unsigned char)(('l'))))) {
677 flags |= NS_COOKIE_SAMESITE_LAX0x40u;
678 } else if (samesite == INTCHAR('n')((int)((unsigned char)(('n'))))) {
679 flags |= NS_COOKIE_SAMESITE_NONE0x80u;
680 }
681
682 /*
683 * Accept expiry time as relative or absolute and adjust to the relative
684 * time Ns_ConnSetCookieEx expects, taking account of the special value
685 * -1 which is short hand for infinite.
686 */
687
688 if (expiresPtr != NULL((void*)0)) {
689 /*
690 * The start time is close enough to "now"
691 */
692 const Ns_Time *nowPtr = Ns_ConnStartTime(conn);
693 if (expiresPtr->sec < 0) {
694 maxage = TIME_T_MAX9223372036854775807L;
695 } else if (expiresPtr->sec > nowPtr->sec) {
696 maxage = (time_t)expiresPtr->sec - (time_t)nowPtr->sec;
697 } else {
698 maxage = expiresPtr->sec;
699 }
700 } else {
701 maxage = 0;
702 }
703
704 Ns_ConnSetCookieEx(conn, name, data, maxage, domain, path, flags);
705 result = TCL_OK0;
706 }
707
708 return result;
709}
710
711
712/*
713 *----------------------------------------------------------------------
714 *
715 * NsTclGetCookieObjCmd --
716 *
717 * Implements "ns_getcookie". The given default will be
718 * returned if no matching cookie exists.
719 *
720 * Results:
721 * Tcl result.
722 *
723 * Side effects:
724 * None.
725 *
726 *----------------------------------------------------------------------
727 */
728
729int
730NsTclGetCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp,
731 int objc, Tcl_Obj *const* objv)
732{
733 Ns_Conn *conn;
734 char *nameString;
735 Tcl_Obj *defaultObj = NULL((void*)0);
736 int status = TCL_OK0;
737 int withSetCookies = (int)NS_FALSE0, withAll = (int)NS_FALSE0;
738
739 Ns_ObjvSpec opts[] = {
740 {"-all", Ns_ObjvBool, &withAll, NULL((void*)0)},
741 {"-include_set_cookies", Ns_ObjvBool, &withSetCookies, NULL((void*)0)},
742 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
743 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
744 };
745 Ns_ObjvSpec args[] = {
746 {"name", Ns_ObjvString, &nameString, NULL((void*)0)},
747 {"?default", Ns_ObjvObj, &defaultObj, NULL((void*)0)},
748 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
749 };
750
751 if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK
752 || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) {
753 status = TCL_ERROR1;
754
755 } else if (withSetCookies == (int)NS_TRUE1 && withAll == (int)NS_TRUE1) {
756 Ns_TclPrintfResult(interp, "%s", "invalid combination of flags -include_set_cookies and -all");
757 status = TCL_ERROR1;
758
759 } else {
760 Ns_DStringTcl_DString ds;
761 int idx = -1;
762
763 Ns_DStringInitTcl_DStringInit(&ds);
764
765 if (withAll == (int)NS_TRUE1) {
766 idx = GetAllNamedCookies(&ds, Ns_ConnHeaders(conn),
767 "cookie", nameString);
768
769 } else {
770 if (withSetCookies == (int)NS_TRUE1) {
771 idx = GetFirstNamedCookie(&ds, Ns_ConnOutputHeaders(conn),
772 "set-cookie", nameString);
773 }
774 if (idx == -1) {
775 idx = GetFirstNamedCookie(&ds, Ns_ConnHeaders(conn),
776 "cookie", nameString);
777 }
778 }
779
780 if (idx != -1) {
781 Tcl_DStringResult(interp, &ds);
782 } else if (defaultObj != NULL((void*)0)) {
783 Tcl_SetObjResult(interp, defaultObj);
784 } else {
785 Tcl_SetObjResult(interp, Tcl_NewStringObj("no such cookie", -1));
786 status = TCL_ERROR1;
787 }
788 Ns_DStringFreeTcl_DStringFree(&ds);
789 }
790
791 return status;
792}
793
794
795/*
796 *----------------------------------------------------------------------
797 *
798 * NsTclDeleteCookieObjCmd --
799 *
800 * Implements "ns_deletecookie".
801 *
802 * Results:
803 * Tcl result.
804 *
805 * Side effects:
806 * See Ns_ConnDeleteCookie().
807 *
808 *----------------------------------------------------------------------
809 */
810
811int
812NsTclDeleteCookieObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp,
813 int objc, Tcl_Obj *const* objv)
814{
815 Ns_Conn *conn;
816 char *name, *domain = NULL((void*)0), *path = NULL((void*)0);
817 int secure = 0, replace = 0, result;
818 int samesite = INTCHAR('l')((int)((unsigned char)(('l'))));
819 Ns_ObjvSpec opts[] = {
820 {"-domain", Ns_ObjvString, &domain, NULL((void*)0)},
821 {"-path", Ns_ObjvString, &path, NULL((void*)0)},
822 {"-replace", Ns_ObjvBool, &replace, NULL((void*)0)},
823 {"-samesite",Ns_ObjvIndex, &samesite, samesiteValues},
824 {"-secure", Ns_ObjvBool, &secure, NULL((void*)0)},
825 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
826 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
827 };
828 Ns_ObjvSpec args[] = {
829 {"name", Ns_ObjvString, &name, NULL((void*)0)},
830 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
831 };
832
833 if (Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK
834 || NsConnRequire(interp, NS_CONN_REQUIRE_CONFIGURED0x0004u, &conn) != NS_OK) {
835 result = TCL_ERROR1;
836
837 } else {
838 unsigned int flags = 0u;
839
840 if (replace != 0) {
841 flags |= NS_COOKIE_REPLACE0x08u;
842 }
843 if (secure != 0) {
844 flags |= NS_COOKIE_SECURE0x01u;
845 }
846
847 /*
848 * If "-samesite none" flag was provided, and secure was not set, fall
849 * back to "-samesite lax" and complain.
850 */
851 if (samesite == INTCHAR('n')((int)((unsigned char)(('n')))) && secure == 0) {
Similar code here
852 Ns_Log(Warning, "cookie '%s': trying to set '-samesite none' "
853 "without the '-secure' flag. Fall back to -samesite lax", name);
854 samesite = INTCHAR('l')((int)((unsigned char)(('l'))));
855 }
856
857 if (samesite == INTCHAR('s')((int)((unsigned char)(('s'))))) {
858 flags |= NS_COOKIE_SAMESITE_STRICT0x20u;
859 } else if (samesite == INTCHAR('l')((int)((unsigned char)(('l'))))) {
860 flags |= NS_COOKIE_SAMESITE_LAX0x40u;
861 } else if (samesite == INTCHAR('n')((int)((unsigned char)(('n'))))) {
862 flags |= NS_COOKIE_SAMESITE_NONE0x80u;
863 }
864
865 Ns_ConnSetCookieEx(conn, name, NULL((void*)0), (time_t)0, domain, path,
866 NS_COOKIE_EXPIRENOW0x10u|flags);
867 result = TCL_OK0;
868 }
869
870 return result;
871}
872
873/*
874 * Local Variables:
875 * mode: c
876 * c-basic-offset: 4
877 * fill-column: 78
878 * indent-tabs-mode: nil
879 * End:
880 */