Skip to content

Commit 4b980d1

Browse files
workingjubileecbandyusamoi
authored
Manually bind static MyProcPort and struct Port (pgcentralfoundation#2162)
This is my proposed alternative to pgcentralfoundation#2117 building on @usamoi's suggestion. In order to enable interacting with `static MyProcPort`, we introduce a definition of the `struct Port` type in `mod libpq` that is available on all versions of Postgres. Several fields are left private to discourage access to them, as in general enabling access to Postgres's cryptography APIs for authentication and authorization is outside the desired project scope of PGRX. In addition, in one (but only one) version, Postgres 17, the result of `size_of::<Port>()` is not even guaranteed to be correct. This is because we don't immediately know, without implementing `cfg(accessible(..))`, whether or not these fields should exist or not. Because of these difficulties, we leave those dubious fields deprecated on Postgres 17 so that no one interacts with them until such time as we gain more confidence in that. Fixes pgcentralfoundation#2157 --------- Co-authored-by: Chris Bandy <[email protected]> Co-authored-by: usamoi <[email protected]>
1 parent 4e64206 commit 4b980d1

2 files changed

Lines changed: 204 additions & 0 deletions

File tree

pgrx-pg-sys/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ mod cstr;
2020
mod include;
2121
mod node;
2222
mod port;
23+
24+
pub mod libpq;
2325
pub mod submodules;
2426

2527
#[cfg(feature = "cshim")]

pgrx-pg-sys/src/libpq.rs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/** Manually-constructed bindings to libpq
2+
3+
Because pgrx is for extensions which run in the Postgres server, it rarely needs access to libpq.
4+
However, some server-side extensions need to interact with the reality that clients exist.
5+
Unfortunately, doing that means acknowledging that clients need authentication and authorization,
6+
areas of concern that are far beyond what pgrx wants to involve itself with or be responsible for.
7+
8+
We define some types and signatures here to allow a minimal amount of usage of items from libpq,
9+
while largely rejecting the notion that we should involve ourselves in security-laden concerns.
10+
11+
*/
12+
13+
pub mod be {
14+
15+
unsafe extern "C" {
16+
pub static mut MyProcPort: *mut Port;
17+
}
18+
19+
/// #define SCRAM_MAX_KEY_LEN PG_SHA256_DIGEST_LENGTH
20+
/// #define PG_SHA256_DIGEST_LENGTH 32
21+
#[cfg(feature = "pg18")]
22+
const SCRAM_MAX_KEY_LEN: usize = 32;
23+
24+
/// Port for Postgres 13..=16
25+
#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15", feature = "pg16"))]
26+
pub struct Port {
27+
pub sock: crate::pgsocket,
28+
pub noblock: bool,
29+
pub proto: crate::ProtocolVersion,
30+
pub laddr: crate::SockAddr,
31+
pub raddr: crate::SockAddr,
32+
pub remote_host: *mut core::ffi::c_char,
33+
pub remote_hostname: *mut core::ffi::c_char,
34+
pub remote_hostname_resolv: core::ffi::c_int,
35+
pub remote_hostname_errcode: core::ffi::c_int,
36+
pub remote_port: *mut core::ffi::c_char,
37+
pub canAcceptConnections: core::ffi::c_uint,
38+
pub database_name: *mut core::ffi::c_char,
39+
pub user_name: *mut core::ffi::c_char,
40+
pub cmdline_options: *mut core::ffi::c_char,
41+
pub guc_options: *mut crate::List,
42+
pub application_name: *mut core::ffi::c_char,
43+
44+
// The remainder is for completeness, so Rust sees Port's layout as correctly as possible.
45+
// Ideally we would use `extern type` so the remainder of this was seen as of unknown size.
46+
// An alternative is to simply treat them as private fields, so we do.
47+
48+
// This should be `*mut crate::HbaLine` if we ever bind that
49+
hba: *mut core::ffi::c_void,
50+
51+
#[cfg(any(feature = "pg14", feature = "pg15"))]
52+
authn_id: *const core::ffi::c_char,
53+
54+
default_keepalives_idle: core::ffi::c_int,
55+
default_keepalives_interval: core::ffi::c_int,
56+
default_keepalives_count: core::ffi::c_int,
57+
default_tcp_user_timeout: core::ffi::c_int,
58+
keepalives_idle: core::ffi::c_int,
59+
keepalives_interval: core::ffi::c_int,
60+
keepalives_count: core::ffi::c_int,
61+
tcp_user_timeout: core::ffi::c_int,
62+
63+
// as if ENABLE_GSS == false && ENABLE_SSPI == false
64+
gss: *mut core::ffi::c_void,
65+
66+
ssl_in_use: bool,
67+
peer_cn: *mut core::ffi::c_char,
68+
#[cfg(any(feature = "pg14", feature = "pg15", feature = "pg16"))]
69+
peer_dn: *mut core::ffi::c_char,
70+
peer_cert_valid: bool,
71+
}
72+
73+
/// Port for Postgres 17
74+
#[cfg(feature = "pg17")]
75+
#[repr(C)]
76+
pub struct Port {
77+
pub sock: crate::pgsocket,
78+
pub noblock: bool,
79+
pub proto: crate::ProtocolVersion,
80+
pub laddr: crate::SockAddr,
81+
pub raddr: crate::SockAddr,
82+
pub remote_host: *mut core::ffi::c_char,
83+
pub remote_hostname: *mut core::ffi::c_char,
84+
pub remote_hostname_resolv: core::ffi::c_int,
85+
pub remote_hostname_errcode: core::ffi::c_int,
86+
pub remote_port: *mut core::ffi::c_char,
87+
pub canAcceptConnections: core::ffi::c_uint,
88+
pub database_name: *mut core::ffi::c_char,
89+
pub user_name: *mut core::ffi::c_char,
90+
pub cmdline_options: *mut core::ffi::c_char,
91+
pub guc_options: *mut crate::List,
92+
pub application_name: *mut core::ffi::c_char,
93+
94+
// The remainder is for completeness, so Rust sees Port's layout as correctly as possible.
95+
// Ideally we would use `extern type` so the remainder of this was seen as of unknown size.
96+
// An alternative is to simply treat them as private fields, so we do.
97+
98+
// This should be `*mut crate::HbaLine` if we ever bind that
99+
hba: *mut core::ffi::c_void,
100+
101+
default_keepalives_idle: core::ffi::c_int,
102+
default_keepalives_interval: core::ffi::c_int,
103+
default_keepalives_count: core::ffi::c_int,
104+
default_tcp_user_timeout: core::ffi::c_int,
105+
keepalives_idle: core::ffi::c_int,
106+
keepalives_interval: core::ffi::c_int,
107+
keepalives_count: core::ffi::c_int,
108+
tcp_user_timeout: core::ffi::c_int,
109+
110+
// as if ENABLE_GSS == false && ENABLE_SSPI == false
111+
gss: *mut core::ffi::c_void,
112+
113+
ssl_in_use: bool,
114+
peer_cn: *mut core::ffi::c_char,
115+
peer_cert_valid: bool,
116+
117+
alpn_used: bool,
118+
119+
// NOTE: 5 fields remain on PG17, but two are `#ifdef USE_OPENSSL` in Postgres 17,
120+
// which is complicated to correctly compile due to needing to implement `cfg(accessible)`
121+
#[cfg(false)]
122+
ssl: *mut core::ffi::c_void,
123+
#[cfg(false)]
124+
peer: *mut core::ffi::c_void,
125+
126+
#[deprecated(
127+
since = "0.17.0",
128+
note = "may be incorrect on Postgres 17 depending on build `#define`s"
129+
)]
130+
raw_buf: *mut core::ffi::c_char,
131+
#[deprecated(
132+
since = "0.17.0",
133+
note = "may be incorrect to access on Postgres 17 depending on build `#define`s"
134+
)]
135+
raw_buf_consumed: isize,
136+
#[deprecated(
137+
since = "0.17.0",
138+
note = "may be incorrect to access on Postgres 17 depending on build `#define`s"
139+
)]
140+
raw_buf_remaining: isize,
141+
}
142+
143+
/// Port for Postgres 18..
144+
#[cfg(feature = "pg18")]
145+
#[repr(C)]
146+
pub struct Port {
147+
pub sock: crate::pgsocket,
148+
pub noblock: bool,
149+
pub proto: crate::ProtocolVersion,
150+
pub laddr: crate::SockAddr,
151+
pub raddr: crate::SockAddr,
152+
pub remote_host: *mut core::ffi::c_char,
153+
pub remote_hostname: *mut core::ffi::c_char,
154+
pub remote_hostname_resolv: core::ffi::c_int,
155+
pub remote_hostname_errcode: core::ffi::c_int,
156+
pub remote_port: *mut core::ffi::c_char,
157+
pub local_host: [core::ffi::c_char; 64],
158+
pub database_name: *mut core::ffi::c_char,
159+
pub user_name: *mut core::ffi::c_char,
160+
pub cmdline_options: *mut core::ffi::c_char,
161+
pub guc_options: *mut crate::List,
162+
pub application_name: *mut core::ffi::c_char,
163+
164+
// The remainder is for completeness, so Rust sees Port's layout as correctly as possible.
165+
// Ideally we would use `extern type` so the remainder of this was seen as of unknown size.
166+
// An alternative is to simply treat them as private fields, so we do.
167+
168+
// This should be `*mut crate::HbaLine` if we ever bind that
169+
hba: *mut core::ffi::c_void,
170+
171+
default_keepalives_idle: core::ffi::c_int,
172+
default_keepalives_interval: core::ffi::c_int,
173+
default_keepalives_count: core::ffi::c_int,
174+
default_tcp_user_timeout: core::ffi::c_int,
175+
keepalives_idle: core::ffi::c_int,
176+
keepalives_interval: core::ffi::c_int,
177+
keepalives_count: core::ffi::c_int,
178+
tcp_user_timeout: core::ffi::c_int,
179+
180+
scram_ClientKey: [u8; SCRAM_MAX_KEY_LEN],
181+
scram_ServerKey: [u8; SCRAM_MAX_KEY_LEN],
182+
has_scram_keys: bool,
183+
184+
// as if ENABLE_GSS == false && ENABLE_SSPI == false
185+
gss: *mut core::ffi::c_void,
186+
187+
ssl_in_use: bool,
188+
peer_cn: *mut core::ffi::c_char,
189+
peer_cert_valid: bool,
190+
191+
alpn_used: bool,
192+
last_read_was_eof: bool,
193+
194+
// as if USE_OPENSSL == false
195+
ssl: *mut core::ffi::c_void,
196+
peer: *mut core::ffi::c_void,
197+
198+
raw_buf: *mut core::ffi::c_char,
199+
raw_buf_consumed: isize,
200+
raw_buf_remaining: isize,
201+
}
202+
}

0 commit comments

Comments
 (0)