Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * fe-secure.c
4 : * functions related to setting up a secure connection to the backend.
5 : * Secure connections are expected to provide confidentiality,
6 : * message integrity and endpoint authentication.
7 : *
8 : *
9 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
10 : * Portions Copyright (c) 1994, Regents of the University of California
11 : *
12 : *
13 : * IDENTIFICATION
14 : * src/interfaces/libpq/fe-secure.c
15 : *
16 : *-------------------------------------------------------------------------
17 : */
18 :
19 : #include "postgres_fe.h"
20 :
21 : #include <signal.h>
22 : #include <fcntl.h>
23 : #include <ctype.h>
24 :
25 : #ifdef WIN32
26 : #include "win32.h"
27 : #else
28 : #include <sys/socket.h>
29 : #include <unistd.h>
30 : #include <netdb.h>
31 : #include <netinet/in.h>
32 : #include <netinet/tcp.h>
33 : #include <arpa/inet.h>
34 : #endif
35 :
36 : #include <sys/stat.h>
37 :
38 : #ifdef ENABLE_THREAD_SAFETY
39 : #ifdef WIN32
40 : #include "pthread-win32.h"
41 : #else
42 : #include <pthread.h>
43 : #endif
44 : #endif
45 :
46 : #include "fe-auth.h"
47 : #include "libpq-fe.h"
48 : #include "libpq-int.h"
49 :
50 : /*
51 : * Macros to handle disabling and then restoring the state of SIGPIPE handling.
52 : * On Windows, these are all no-ops since there's no SIGPIPEs.
53 : */
54 :
55 : #ifndef WIN32
56 :
57 : #define SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag)
58 :
59 : #ifdef ENABLE_THREAD_SAFETY
60 :
61 : struct sigpipe_info
62 : {
63 : sigset_t oldsigmask;
64 : bool sigpipe_pending;
65 : bool got_epipe;
66 : };
67 :
68 : #define DECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo
69 :
70 : #define DISABLE_SIGPIPE(conn, spinfo, failaction) \
71 : do { \
72 : (spinfo).got_epipe = false; \
73 : if (!SIGPIPE_MASKED(conn)) \
74 : { \
75 : if (pq_block_sigpipe(&(spinfo).oldsigmask, \
76 : &(spinfo).sigpipe_pending) < 0) \
77 : failaction; \
78 : } \
79 : } while (0)
80 :
81 : #define REMEMBER_EPIPE(spinfo, cond) \
82 : do { \
83 : if (cond) \
84 : (spinfo).got_epipe = true; \
85 : } while (0)
86 :
87 : #define RESTORE_SIGPIPE(conn, spinfo) \
88 : do { \
89 : if (!SIGPIPE_MASKED(conn)) \
90 : pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \
91 : (spinfo).got_epipe); \
92 : } while (0)
93 : #else /* !ENABLE_THREAD_SAFETY */
94 :
95 : #define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL
96 :
97 : #define DISABLE_SIGPIPE(conn, spinfo, failaction) \
98 : do { \
99 : if (!SIGPIPE_MASKED(conn)) \
100 : spinfo = pqsignal(SIGPIPE, SIG_IGN); \
101 : } while (0)
102 :
103 : #define REMEMBER_EPIPE(spinfo, cond)
104 :
105 : #define RESTORE_SIGPIPE(conn, spinfo) \
106 : do { \
107 : if (!SIGPIPE_MASKED(conn)) \
108 : pqsignal(SIGPIPE, spinfo); \
109 : } while (0)
110 : #endif /* ENABLE_THREAD_SAFETY */
111 : #else /* WIN32 */
112 :
113 : #define DECLARE_SIGPIPE_INFO(spinfo)
114 : #define DISABLE_SIGPIPE(conn, spinfo, failaction)
115 : #define REMEMBER_EPIPE(spinfo, cond)
116 : #define RESTORE_SIGPIPE(conn, spinfo)
117 : #endif /* WIN32 */
118 :
119 : /* ------------------------------------------------------------ */
120 : /* Procedures common to all secure sessions */
121 : /* ------------------------------------------------------------ */
122 :
6702 tgl 123 ECB :
124 : int
1906 peter_e 125 CBC 2 : PQsslInUse(PGconn *conn)
1906 peter_e 126 EUB : {
1906 peter_e 127 CBC 2 : if (!conn)
1906 peter_e 128 UIC 0 : return 0;
1906 peter_e 129 GIC 2 : return conn->ssl_in_use;
130 : }
131 :
132 : /*
133 : * Exported function to allow application to tell us it's already
134 : * initialized OpenSSL.
6702 tgl 135 EUB : */
136 : void
6702 tgl 137 UIC 0 : PQinitSSL(int do_init)
5122 tgl 138 EUB : {
139 : #ifdef USE_SSL
3163 heikki.linnakangas 140 UBC 0 : pgtls_init_library(do_init, do_init);
141 : #endif
5122 tgl 142 UIC 0 : }
143 :
144 : /*
145 : * Exported function to allow application to tell us it's already
146 : * initialized OpenSSL and/or libcrypto.
5122 tgl 147 EUB : */
148 : void
5122 tgl 149 UIC 0 : PQinitOpenSSL(int do_ssl, int do_crypto)
6702 tgl 150 EUB : {
151 : #ifdef USE_SSL
3163 heikki.linnakangas 152 UBC 0 : pgtls_init_library(do_ssl, do_crypto);
153 : #endif
6702 tgl 154 UIC 0 : }
155 :
156 : /*
157 : * Initialize global SSL context
7604 bruce 158 ECB : */
159 : int
759 michael 160 CBC 9302 : pqsecure_initialize(PGconn *conn, bool do_ssl, bool do_crypto)
161 : {
7522 bruce 162 GIC 9302 : int r = 0;
7604 bruce 163 ECB :
164 : #ifdef USE_SSL
759 michael 165 GIC 9302 : r = pgtls_init(conn, do_ssl, do_crypto);
7604 bruce 166 ECB : #endif
167 :
7604 bruce 168 GIC 9302 : return r;
169 : }
170 :
171 : /*
172 : * Begin or continue negotiating a secure session.
7604 bruce 173 ECB : */
174 : PostgresPollingStatusType
7522 bruce 175 GIC 305 : pqsecure_open_client(PGconn *conn)
7604 bruce 176 ECB : {
177 : #ifdef USE_SSL
3163 heikki.linnakangas 178 GIC 305 : return pgtls_open_client(conn);
179 : #else
180 : /* shouldn't get here */
181 : return PGRES_POLLING_FAILED;
182 : #endif
183 : }
184 :
185 : /*
186 : * Close secure session.
7604 bruce 187 ECB : */
188 : void
7522 bruce 189 GIC 18875 : pqsecure_close(PGconn *conn)
7604 bruce 190 ECB : {
191 : #ifdef USE_SSL
759 michael 192 CBC 18875 : pgtls_close(conn);
193 : #endif
7604 bruce 194 GIC 18875 : }
195 :
196 : /*
197 : * Read data from a secure connection.
198 : *
199 : * On failure, this function is responsible for appending a suitable message
200 : * to conn->errorMessage. The caller must still inspect errno, but only
201 : * to determine whether to continue/retry after error.
7604 bruce 202 ECB : */
203 : ssize_t
7522 bruce 204 GIC 858474 : pqsecure_read(PGconn *conn, void *ptr, size_t len)
205 : {
206 : ssize_t n;
7604 bruce 207 ECB :
208 : #ifdef USE_SSL
3163 heikki.linnakangas 209 CBC 858474 : if (conn->ssl_in_use)
210 : {
3163 heikki.linnakangas 211 GIC 365 : n = pgtls_read(conn, ptr, len);
212 : }
213 : else
1467 sfrost 214 ECB : #endif
215 : #ifdef ENABLE_GSS
1467 sfrost 216 CBC 858109 : if (conn->gssenc)
217 : {
1467 sfrost 218 GIC 250 : n = pg_GSS_read(conn, ptr, len);
219 : }
220 : else
3163 heikki.linnakangas 221 ECB : #endif
222 : {
3163 heikki.linnakangas 223 GIC 857859 : n = pqsecure_raw_read(conn, ptr, len);
3163 heikki.linnakangas 224 ECB : }
225 :
3163 heikki.linnakangas 226 GIC 858474 : return n;
227 : }
6797 bruce 228 ECB :
229 : ssize_t
3163 heikki.linnakangas 230 GIC 861206 : pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
3163 heikki.linnakangas 231 ECB : {
232 : ssize_t n;
3163 heikki.linnakangas 233 GIC 861206 : int result_errno = 0;
1656 tgl 234 ECB : char sebuf[PG_STRERROR_R_BUFLEN];
235 :
3163 heikki.linnakangas 236 CBC 861206 : n = recv(conn->sock, ptr, len, 0);
237 :
238 861206 : if (n < 0)
239 : {
3163 heikki.linnakangas 240 GIC 286167 : result_errno = SOCK_ERRNO;
7604 bruce 241 ECB :
242 : /* Set error message if appropriate */
3163 heikki.linnakangas 243 GIC 286167 : switch (result_errno)
4277 tgl 244 ECB : {
245 : #ifdef EAGAIN
3163 heikki.linnakangas 246 GIC 286166 : case EAGAIN:
247 : #endif
248 : #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
249 : case EWOULDBLOCK:
250 : #endif
3163 heikki.linnakangas 251 ECB : case EINTR:
252 : /* no error message, caller is expected to retry */
3163 heikki.linnakangas 253 CBC 286166 : break;
254 :
911 tgl 255 1 : case EPIPE:
256 : case ECONNRESET:
145 peter 257 GNC 1 : libpq_append_conn_error(conn, "server closed the connection unexpectedly\n"
258 : "\tThis probably means the server terminated abnormally\n"
259 : "\tbefore or while processing the request.");
3163 heikki.linnakangas 260 GBC 1 : break;
261 :
3163 heikki.linnakangas 262 UIC 0 : default:
145 peter 263 UNC 0 : libpq_append_conn_error(conn, "could not receive data from server: %s",
264 : SOCK_STRERROR(result_errno,
265 : sebuf, sizeof(sebuf)));
3163 heikki.linnakangas 266 UIC 0 : break;
4277 tgl 267 ECB : }
268 : }
269 :
270 : /* ensure we return the intended errno to caller */
4277 tgl 271 GIC 861206 : SOCK_ERRNO_SET(result_errno);
272 :
7604 bruce 273 861206 : return n;
274 : }
275 :
276 : /*
277 : * Write data to a secure connection.
278 : *
279 : * Returns the number of bytes written, or a negative value (with errno
280 : * set) upon failure. The write count could be less than requested.
281 : *
282 : * Note that socket-level hard failures are masked from the caller,
283 : * instead setting conn->write_failed and storing an error message
284 : * in conn->write_err_msg; see pqsecure_raw_write. This allows us to
285 : * postpone reporting of write failures until we're sure no error
286 : * message is available from the server.
287 : *
288 : * However, errors detected in the SSL or GSS management level are reported
289 : * via a negative result, with message appended to conn->errorMessage.
290 : * It's frequently unclear whether such errors should be considered read or
291 : * write errors, so we don't attempt to postpone reporting them.
292 : *
421 tgl 293 ECB : * The caller must still inspect errno upon failure, but only to determine
294 : * whether to continue/retry; a message has been saved someplace in any case.
295 : */
296 : ssize_t
7522 bruce 297 GIC 364948 : pqsecure_write(PGconn *conn, const void *ptr, size_t len)
7604 bruce 298 ECB : {
299 : ssize_t n;
6385 300 :
301 : #ifdef USE_SSL
3163 heikki.linnakangas 302 GIC 364948 : if (conn->ssl_in_use)
303 : {
304 256 : n = pgtls_write(conn, ptr, len);
7604 bruce 305 ECB : }
306 : else
1467 sfrost 307 : #endif
308 : #ifdef ENABLE_GSS
1467 sfrost 309 GIC 364692 : if (conn->gssenc)
310 : {
311 122 : n = pg_GSS_write(conn, ptr, len);
1467 sfrost 312 ECB : }
313 : else
314 : #endif
6702 tgl 315 : {
3163 heikki.linnakangas 316 GIC 364570 : n = pqsecure_raw_write(conn, ptr, len);
317 : }
318 :
319 364948 : return n;
320 : }
321 :
322 : /*
323 : * Low-level implementation of pqsecure_write.
324 : *
325 : * This is used directly for an unencrypted connection. For encrypted
326 : * connections, this does the physical I/O on behalf of pgtls_write or
327 : * pg_GSS_write.
328 : *
329 : * This function reports failure (i.e., returns a negative result) only
330 : * for retryable errors such as EINTR. Looping for such cases is to be
331 : * handled at some outer level, maybe all the way up to the application.
332 : * For hard failures, we set conn->write_failed and store an error message
333 : * in conn->write_err_msg, but then claim to have written the data anyway.
334 : * This is because we don't want to report write failures so long as there
335 : * is a possibility of reading from the server and getting an error message
336 : * that could explain why the connection dropped. Many TCP stacks have
337 : * race conditions such that a write failure may or may not be reported
338 : * before all incoming data has been read.
339 : *
340 : * Note that this error behavior happens below the SSL management level when
341 : * we are using SSL. That's because at least some versions of OpenSSL are
421 tgl 342 ECB : * too quick to report a write failure when there's still a possibility to
343 : * get a more useful error from the server.
344 : */
3163 heikki.linnakangas 345 : ssize_t
3163 heikki.linnakangas 346 CBC 365397 : pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len)
347 : {
348 : ssize_t n;
3163 heikki.linnakangas 349 GIC 365397 : int flags = 0;
350 365397 : int result_errno = 0;
351 : char msgbuf[1024];
352 : char sebuf[PG_STRERROR_R_BUFLEN];
353 :
354 : DECLARE_SIGPIPE_INFO(spinfo);
355 :
356 : /*
357 : * If we already had a write failure, we will never again try to send data
358 : * on that connection. Even if the kernel would let us, we've probably
421 tgl 359 ECB : * lost message boundary sync with the server. conn->write_failed
421 tgl 360 EUB : * therefore persists until the connection is reset, and we just discard
361 : * all data presented to be written.
362 : */
421 tgl 363 CBC 365397 : if (conn->write_failed)
421 tgl 364 LBC 0 : return len;
365 :
5007 tgl 366 ECB : #ifdef MSG_NOSIGNAL
3163 heikki.linnakangas 367 GIC 365397 : if (conn->sigpipe_flag)
368 365397 : flags |= MSG_NOSIGNAL;
5007 tgl 369 ECB :
5007 tgl 370 GIC 365397 : retry_masked:
2118 tgl 371 ECB : #endif /* MSG_NOSIGNAL */
372 :
3163 heikki.linnakangas 373 CBC 365397 : DISABLE_SIGPIPE(conn, spinfo, return -1);
374 :
375 365397 : n = send(conn->sock, ptr, len, flags);
376 :
3163 heikki.linnakangas 377 GIC 365397 : if (n < 0)
378 : {
379 3651 : result_errno = SOCK_ERRNO;
380 :
381 : /*
382 : * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't available
2878 bruce 383 ECB : * on this machine. So, clear sigpipe_flag so we don't try the flag
384 : * again, and retry the send().
3163 heikki.linnakangas 385 EUB : */
5007 tgl 386 : #ifdef MSG_NOSIGNAL
3163 heikki.linnakangas 387 GBC 3651 : if (flags != 0 && result_errno == EINVAL)
388 : {
3163 heikki.linnakangas 389 UIC 0 : conn->sigpipe_flag = false;
390 0 : flags = 0;
391 0 : goto retry_masked;
3163 heikki.linnakangas 392 ECB : }
393 : #endif /* MSG_NOSIGNAL */
394 :
395 : /* Set error message if appropriate */
3163 heikki.linnakangas 396 GIC 3651 : switch (result_errno)
397 : {
398 : #ifdef EAGAIN
399 3641 : case EAGAIN:
400 : #endif
401 : #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
3163 heikki.linnakangas 402 ECB : case EWOULDBLOCK:
403 : #endif
404 : case EINTR:
405 : /* no error message, caller is expected to retry */
3163 heikki.linnakangas 406 CBC 3641 : break;
407 :
3163 heikki.linnakangas 408 GIC 10 : case EPIPE:
409 : /* Set flag for EPIPE */
410 10 : REMEMBER_EPIPE(spinfo, true);
4277 tgl 411 ECB :
412 : /* FALL THRU */
413 :
3163 heikki.linnakangas 414 : case ECONNRESET:
421 tgl 415 CBC 10 : conn->write_failed = true;
416 : /* Store error message in conn->write_err_msg, if possible */
417 : /* (strdup failure is OK, we'll cope later) */
421 tgl 418 GIC 10 : snprintf(msgbuf, sizeof(msgbuf),
421 tgl 419 CBC 10 : libpq_gettext("server closed the connection unexpectedly\n"
421 tgl 420 ECB : "\tThis probably means the server terminated abnormally\n"
421 : "\tbefore or while processing the request."));
422 : /* keep newline out of translated string */
145 peter 423 GNC 10 : strlcat(msgbuf, "\n", sizeof(msgbuf));
421 tgl 424 CBC 10 : conn->write_err_msg = strdup(msgbuf);
421 tgl 425 ECB : /* Now claim the write succeeded */
421 tgl 426 GIC 10 : n = len;
3163 heikki.linnakangas 427 GBC 10 : break;
4277 tgl 428 EUB :
3163 heikki.linnakangas 429 UIC 0 : default:
421 tgl 430 0 : conn->write_failed = true;
421 tgl 431 EUB : /* Store error message in conn->write_err_msg, if possible */
432 : /* (strdup failure is OK, we'll cope later) */
421 tgl 433 UIC 0 : snprintf(msgbuf, sizeof(msgbuf),
145 peter 434 UNC 0 : libpq_gettext("could not send data to server: %s"),
435 : SOCK_STRERROR(result_errno,
421 tgl 436 EUB : sebuf, sizeof(sebuf)));
437 : /* keep newline out of translated string */
145 peter 438 UNC 0 : strlcat(msgbuf, "\n", sizeof(msgbuf));
421 tgl 439 UBC 0 : conn->write_err_msg = strdup(msgbuf);
440 : /* Now claim the write succeeded */
441 0 : n = len;
3163 heikki.linnakangas 442 0 : break;
443 : }
444 : }
445 :
5007 tgl 446 CBC 365397 : RESTORE_SIGPIPE(conn, spinfo);
447 :
448 : /* ensure we return the intended errno to caller */
4277 449 365397 : SOCK_ERRNO_SET(result_errno);
450 :
7604 bruce 451 365397 : return n;
452 : }
453 :
454 : /* Dummy versions of SSL info functions, when built without SSL support */
455 : #ifndef USE_SSL
456 :
457 : void *
458 : PQgetssl(PGconn *conn)
459 : {
460 : return NULL;
461 : }
462 :
463 : void *
464 : PQsslStruct(PGconn *conn, const char *struct_name)
465 : {
466 : return NULL;
467 : }
468 :
469 : const char *
470 : PQsslAttribute(PGconn *conn, const char *attribute_name)
471 : {
472 : return NULL;
473 : }
474 :
475 : const char *const *
476 : PQsslAttributeNames(PGconn *conn)
477 : {
478 : static const char *const result[] = {NULL};
479 :
480 : return result;
481 : }
482 : #endif /* USE_SSL */
483 :
484 : /*
485 : * Dummy versions of OpenSSL key password hook functions, when built without
486 : * OpenSSL.
487 : */
488 : #ifndef USE_OPENSSL
489 :
490 : PQsslKeyPassHook_OpenSSL_type
491 : PQgetSSLKeyPassHook_OpenSSL(void)
492 : {
493 : return NULL;
494 : }
495 :
496 : void
497 : PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook)
498 : {
499 : return;
500 : }
501 :
502 : int
503 : PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn)
504 : {
505 : return 0;
506 : }
507 : #endif /* USE_OPENSSL */
508 :
509 : /* Dummy version of GSSAPI information functions, when built without GSS support */
510 : #ifndef ENABLE_GSS
511 :
512 : void *
513 : PQgetgssctx(PGconn *conn)
514 : {
515 : return NULL;
516 : }
517 :
518 : int
519 : PQgssEncInUse(PGconn *conn)
520 : {
521 : return 0;
522 : }
523 :
524 : #endif /* ENABLE_GSS */
525 :
526 :
527 : #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
528 :
529 : /*
530 : * Block SIGPIPE for this thread. This prevents send()/write() from exiting
531 : * the application.
532 : */
533 : int
6702 bruce 534 UBC 0 : pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
535 : {
536 : sigset_t sigpipe_sigset;
537 : sigset_t sigset;
538 :
539 0 : sigemptyset(&sigpipe_sigset);
540 0 : sigaddset(&sigpipe_sigset, SIGPIPE);
541 :
542 : /* Block SIGPIPE and save previous mask for later reset */
tgl 543 0 : SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset));
544 0 : if (SOCK_ERRNO)
545 0 : return -1;
546 :
547 : /* We can have a pending SIGPIPE only if it was blocked before */
bruce 548 0 : if (sigismember(osigset, SIGPIPE))
549 : {
550 : /* Is there a pending SIGPIPE? */
551 0 : if (sigpending(&sigset) != 0)
552 0 : return -1;
553 :
554 0 : if (sigismember(&sigset, SIGPIPE))
555 0 : *sigpipe_pending = true;
556 : else
557 0 : *sigpipe_pending = false;
558 : }
559 : else
560 0 : *sigpipe_pending = false;
561 :
tgl 562 0 : return 0;
563 : }
564 :
565 : /*
566 : * Discard any pending SIGPIPE and reset the signal mask.
567 : *
568 : * Note: we are effectively assuming here that the C library doesn't queue
569 : * up multiple SIGPIPE events. If it did, then we'd accidentally leave
570 : * ours in the queue when an event was already pending and we got another.
571 : * As long as it doesn't queue multiple events, we're OK because the caller
572 : * can't tell the difference.
573 : *
574 : * The caller should say got_epipe = false if it is certain that it
575 : * didn't get an EPIPE error; in that case we'll skip the clear operation
576 : * and things are definitely OK, queuing or no. If it got one or might have
577 : * gotten one, pass got_epipe = true.
578 : *
579 : * We do not want this to change errno, since if it did that could lose
580 : * the error code from a preceding send(). We essentially assume that if
581 : * we were able to do pq_block_sigpipe(), this can't fail.
582 : */
583 : void
584 0 : pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
585 : {
6385 bruce 586 0 : int save_errno = SOCK_ERRNO;
587 : int signo;
588 : sigset_t sigset;
589 :
590 : /* Clear SIGPIPE only if none was pending */
6702 tgl 591 0 : if (got_epipe && !sigpipe_pending)
592 : {
593 0 : if (sigpending(&sigset) == 0 &&
594 0 : sigismember(&sigset, SIGPIPE))
595 : {
596 : sigset_t sigpipe_sigset;
597 :
bruce 598 0 : sigemptyset(&sigpipe_sigset);
599 0 : sigaddset(&sigpipe_sigset, SIGPIPE);
600 :
601 0 : sigwait(&sigpipe_sigset, &signo);
602 : }
603 : }
604 :
605 : /* Restore saved block mask */
tgl 606 0 : pthread_sigmask(SIG_SETMASK, osigset, NULL);
607 :
608 0 : SOCK_ERRNO_SET(save_errno);
7030 bruce 609 0 : }
610 :
611 : #endif /* ENABLE_THREAD_SAFETY && !WIN32 */
|