📄 fe-secure.c
字号:
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); SOCK_ERRNO_SET(ECONNRESET); n = -1; } break; } case SSL_ERROR_SSL: { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); } /* fall through */ case SSL_ERROR_ZERO_RETURN: SOCK_ERRNO_SET(ECONNRESET); n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); n = -1; break; } } else#endif { n = send(conn->sock, ptr, len, 0);#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) if (n < 0 && SOCK_ERRNO == EPIPE) got_epipe = true;#endif }#ifndef WIN32#ifdef ENABLE_THREAD_SAFETY pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe);#else pqsignal(SIGPIPE, oldsighandler);#endif /* ENABLE_THREAD_SAFETY */#endif /* WIN32 */ return n;}/* ------------------------------------------------------------ *//* SSL specific code *//* ------------------------------------------------------------ */#ifdef USE_SSL/* * Certificate verification callback * * This callback allows us to log intermediate problems during * verification, but there doesn't seem to be a clean way to get * our PGconn * structure. So we can't log anything! * * This callback also allows us to override the default acceptance * criteria (e.g., accepting self-signed or expired certs), but * for now we accept the default checks. */static intverify_cb(int ok, X509_STORE_CTX *ctx){ return ok;}#ifdef NOT_USED/* * Verify that common name resolves to peer. */static intverify_peer(PGconn *conn){ struct hostent *h = NULL; struct sockaddr addr; struct sockaddr_in *sin; ACCEPT_TYPE_ARG3 len; char **s; unsigned long l; /* get the address on the other side of the socket */ len = sizeof(addr); if (getpeername(conn->sock, &addr, &len) == -1) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("error querying socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } /* weird, but legal case */ if (addr.sa_family == AF_UNIX) return 0; { struct hostent hpstr; char buf[BUFSIZ]; int herrno = 0; /* * Currently, pqGethostbyname() is used only on platforms that don't * have getaddrinfo(). If you enable this function, you should * convert the pqGethostbyname() function call to use getaddrinfo(). */ pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf), &h, &herrno); } /* what do we know about the peer's common name? */ if (h == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get information about host \"%s\": %s\n"), conn->peer_cn, hstrerror(h_errno)); return -1; } /* does the address match? */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; for (s = h->h_addr_list; *s != NULL; s++) { if (!memcmp(&sin->sin_addr.s_addr, *s, h->h_length)) return 0; } break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unsupported protocol\n")); return -1; } /* * the prior test should be definitive, but in practice it sometimes * fails. So we also check the aliases. */ for (s = h->h_aliases; *s != NULL; s++) { if (pg_strcasecmp(conn->peer_cn, *s) == 0) return 0; } /* generate protocol-aware error message */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; l = ntohl(sin->sin_addr.s_addr); printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n"), conn->peer_cn, (l >> 24) % 0x100, (l >> 16) % 0x100, (l >> 8) % 0x100, l % 0x100); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to peer address\n"), conn->peer_cn); } return -1;}#endif /* NOT_USED *//* * Load precomputed DH parameters. * * To prevent "downgrade" attacks, we perform a number of checks * to verify that the DBA-generated DH parameters file contains * what we expect it to contain. */static DH *load_dh_file(int keylength){ char homedir[MAXPGPATH]; char fnbuf[MAXPGPATH]; FILE *fp; DH *dh; int codes; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) return NULL; /* attempt to open file. It's not an error if it doesn't exist. */ snprintf(fnbuf, sizeof(fnbuf), DHFILEPATTERN, homedir, keylength); if ((fp = fopen(fnbuf, "r")) == NULL) return NULL;/* flock(fileno(fp), LOCK_SH); */ dh = PEM_read_DHparams(fp, NULL, NULL, NULL);/* flock(fileno(fp), LOCK_UN); */ fclose(fp); /* is the prime the correct size? */ if (dh != NULL && 8 * DH_size(dh) < keylength) dh = NULL; /* make sure the DH parameters are usable */ if (dh != NULL) { if (DH_check(dh, &codes)) return NULL; if (codes & DH_CHECK_P_NOT_PRIME) return NULL; if ((codes & DH_NOT_SUITABLE_GENERATOR) && (codes & DH_CHECK_P_NOT_SAFE_PRIME)) return NULL; } return dh;}/* * Load hardcoded DH parameters. * * To prevent problems if the DH parameters files don't even * exist, we can load DH parameters hardcoded into this file. */static DH *load_dh_buffer(const char *buffer, size_t len){ BIO *bio; DH *dh = NULL; bio = BIO_new_mem_buf((char *) buffer, len); if (bio == NULL) return NULL; dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); return dh;}/* * Generate an empheral DH key. Because this can take a long * time to compute, we can use precomputed parameters of the * common key sizes. * * Since few sites will bother to precompute these parameter * files, we also provide a fallback to the parameters provided * by the OpenSSL project. * * These values can be static (once loaded or computed) since * the OpenSSL library can efficiently generate random keys from * the information provided. */static DH *tmp_dh_cb(SSL *s, int is_export, int keylength){ DH *r = NULL; static DH *dh = NULL; static DH *dh512 = NULL; static DH *dh1024 = NULL; static DH *dh2048 = NULL; static DH *dh4096 = NULL; switch (keylength) { case 512: if (dh512 == NULL) dh512 = load_dh_file(keylength); if (dh512 == NULL) dh512 = load_dh_buffer(file_dh512, sizeof file_dh512); r = dh512; break; case 1024: if (dh1024 == NULL) dh1024 = load_dh_file(keylength); if (dh1024 == NULL) dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024); r = dh1024; break; case 2048: if (dh2048 == NULL) dh2048 = load_dh_file(keylength); if (dh2048 == NULL) dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048); r = dh2048; break; case 4096: if (dh4096 == NULL) dh4096 = load_dh_file(keylength); if (dh4096 == NULL) dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096); r = dh4096; break; default: if (dh == NULL) dh = load_dh_file(keylength); r = dh; } /* this may take a long time, but it may be necessary... */ if (r == NULL || 8 * DH_size(r) < keylength) r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL); return r;}/* * Callback used by SSL to load client cert and key. * This callback is only called when the server wants a * client cert. * * Must return 1 on success, 0 on no data or error. */static intclient_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey){ char homedir[MAXPGPATH]; struct stat buf;#ifndef WIN32 struct stat buf2;#endif char fnbuf[MAXPGPATH]; FILE *fp; PGconn *conn = (PGconn *) SSL_get_app_data(ssl); int (*cb) () = NULL; /* how to read user password */ char sebuf[256]; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get user information\n")); return 0; } /* read the user certificate */ snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USERCERTFILE); if ((fp = fopen(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return 0; } if (PEM_read_X509(fp, x509, NULL, NULL) == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); fclose(fp); return 0; } fclose(fp); /* read the user key */ snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USERKEYFILE); if (stat(fnbuf, &buf) == -1) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate present, but not private key file \"%s\"\n"), fnbuf); return 0; }#ifndef WIN32 if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) || buf.st_uid != geteuid()) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" has wrong permissions\n"), fnbuf); return 0; }#endif if ((fp = fopen(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open private key file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return 0; }#ifndef WIN32 if (fstat(fileno(fp), &buf2) == -1 || buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf); return 0; }#endif if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); fclose(fp); return 0; } fclose(fp); /* verify that the cert and key go together */ if (!X509_check_private_key(*x509, *pkey)) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate does not match private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); return 0; } return 1;}#ifdef ENABLE_THREAD_SAFETYstatic unsigned longpq_threadidcallback(void){ /* * This is not starndard-compliant. pthread_self() returns pthread_t, and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -