Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * oauth-debug.h
4 : * Parsing logic for PGOAUTHDEBUG environment variable
5 : *
6 : * Both libpq and libpq-oauth need this logic, so it's packaged in a small
7 : * header for convenience. This is not quite a standalone header, due to the
8 : * complication introduced by libpq_gettext(); see note below.
9 : *
10 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11 : * Portions Copyright (c) 1994, Regents of the University of California
12 : *
13 : * IDENTIFICATION
14 : * src/interfaces/libpq/oauth-debug.h
15 : *
16 : *-------------------------------------------------------------------------
17 : */
18 :
19 : #ifndef OAUTH_DEBUG_H
20 : #define OAUTH_DEBUG_H
21 :
22 : #include "postgres_fe.h"
23 :
24 : /*
25 : * XXX libpq-oauth can't compile against libpq-int.h, so clients of this header
26 : * need to provide the declaration of libpq_gettext() before #including it.
27 : * Fortunately, there are only two such clients.
28 : */
29 : /* #include "libpq-int.h" */
30 :
31 : /*
32 : * Debug flags for the PGOAUTHDEBUG environment variable. Each flag controls a
33 : * specific debug feature. OAUTHDEBUG_UNSAFE_* flags require the envvar to have
34 : * a literal "UNSAFE:" prefix.
35 : */
36 :
37 : /* allow HTTP (unencrypted) connections */
38 : #define OAUTHDEBUG_UNSAFE_HTTP (1<<0)
39 : /* log HTTP traffic (exposes secrets) */
40 : #define OAUTHDEBUG_UNSAFE_TRACE (1<<1)
41 : /* allow zero-second retry intervals */
42 : #define OAUTHDEBUG_UNSAFE_DOS_ENDPOINT (1<<2)
43 :
44 : /* mind the gap in values; see OAUTHDEBUG_UNSAFE_MASK below */
45 :
46 : /* print PQconnectPoll statistics */
47 : #define OAUTHDEBUG_CALL_COUNT (1<<16)
48 : /* print plugin loading errors */
49 : #define OAUTHDEBUG_PLUGIN_ERRORS (1<<17)
50 :
51 : /* all safe and unsafe flags, for the legacy UNSAFE behavior */
52 : #define OAUTHDEBUG_LEGACY_UNSAFE ((uint32) ~0)
53 :
54 : /* Flags are divided into "safe" and "unsafe" based on bit position. */
55 : #define OAUTHDEBUG_UNSAFE_MASK ((uint32) 0x0000FFFF)
56 :
57 : static_assert(OAUTHDEBUG_CALL_COUNT == OAUTHDEBUG_UNSAFE_MASK + 1,
58 : "the first safe OAUTHDEBUG flag should be above OAUTHDEBUG_UNSAFE_MASK");
59 :
60 : /*
61 : * Parses the PGOAUTHDEBUG environment variable and returns debug flags.
62 : *
63 : * Supported formats:
64 : * PGOAUTHDEBUG=UNSAFE - legacy format, enables all features
65 : * PGOAUTHDEBUG=option1,option2 - enable safe features only
66 : * PGOAUTHDEBUG=UNSAFE:opt1,opt2 - enable unsafe and/or safe features
67 : *
68 : * Prints a warning and skips the invalid option if:
69 : * - An unrecognized option is specified
70 : * - An unsafe option is specified without the UNSAFE: prefix
71 : *
72 : * XXX The parsing, and any warnings, will happen each time the function is
73 : * called, so consider caching the result in cases where that might get
74 : * annoying. But don't try to cache inside this function, unless you also have a
75 : * plan for getting libpq and libpq-oauth to share that cache safely... probably
76 : * not worth the effort for a debugging aid?
77 : */
78 : static uint32
79 0 : oauth_parse_debug_flags(void)
80 : {
81 0 : uint32 flags = 0;
82 0 : const char *env = getenv("PGOAUTHDEBUG");
83 : char *options_str;
84 : char *option;
85 0 : char *saveptr = NULL;
86 0 : bool unsafe_allowed = false;
87 :
88 0 : if (!env || env[0] == '\0')
89 0 : return flags;
90 :
91 0 : if (strcmp(env, "UNSAFE") == 0)
92 0 : return OAUTHDEBUG_LEGACY_UNSAFE;
93 :
94 0 : if (strncmp(env, "UNSAFE:", 7) == 0)
95 : {
96 0 : unsafe_allowed = true;
97 0 : env += 7;
98 : }
99 :
100 0 : options_str = strdup(env);
101 0 : if (!options_str)
102 0 : return flags;
103 :
104 0 : option = strtok_r(options_str, ",", &saveptr);
105 0 : while (option != NULL)
106 : {
107 0 : uint32 flag = 0;
108 :
109 0 : if (strcmp(option, "http") == 0)
110 0 : flag = OAUTHDEBUG_UNSAFE_HTTP;
111 0 : else if (strcmp(option, "trace") == 0)
112 0 : flag = OAUTHDEBUG_UNSAFE_TRACE;
113 0 : else if (strcmp(option, "dos-endpoint") == 0)
114 0 : flag = OAUTHDEBUG_UNSAFE_DOS_ENDPOINT;
115 0 : else if (strcmp(option, "call-count") == 0)
116 0 : flag = OAUTHDEBUG_CALL_COUNT;
117 0 : else if (strcmp(option, "plugin-errors") == 0)
118 0 : flag = OAUTHDEBUG_PLUGIN_ERRORS;
119 : else
120 0 : fprintf(stderr,
121 0 : libpq_gettext("WARNING: unrecognized PGOAUTHDEBUG option \"%s\" (ignored)\n"),
122 : option);
123 :
124 0 : if (!unsafe_allowed && ((flag & OAUTHDEBUG_UNSAFE_MASK) != 0))
125 : {
126 0 : flag = 0;
127 :
128 0 : fprintf(stderr,
129 0 : libpq_gettext("WARNING: PGOAUTHDEBUG option \"%s\" is unsafe (ignored)\n"),
130 : option);
131 : }
132 :
133 0 : flags |= flag;
134 0 : option = strtok_r(NULL, ",", &saveptr);
135 : }
136 :
137 0 : free(options_str);
138 :
139 0 : return flags;
140 : }
141 :
142 : #endif /* OAUTH_DEBUG_H */
|