Skip to content

Commit 61e39c5

Browse files
committed
refactor: add read_file_and_null_terminate helper
1 parent 38a9129 commit 61e39c5

File tree

1 file changed

+84
-43
lines changed

1 file changed

+84
-43
lines changed

src/libmongoc/src/mongoc/mongoc-secure-channel.c

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,92 @@
4141
#define SECBUFFER_ALERT 17
4242
#endif
4343

44+
// `read_file_and_null_terminate` reads a file into a NUL-terminated string.
45+
// On success: returns a NUL-terminated string and (optionally) sets `*out_len` excluding NUL.
46+
// On error: returns NULL.
47+
static char *
48+
read_file_and_null_terminate (const char *filename, size_t *out_len)
49+
{
50+
BSON_ASSERT_PARAM (filename);
51+
BSON_OPTIONAL_PARAM (out_len);
52+
53+
bool ok = false;
54+
char *contents = NULL;
55+
char errmsg_buf[BSON_ERROR_BUFFER_SIZE];
56+
57+
FILE *file = fopen (filename, "rb");
58+
if (!file) {
59+
MONGOC_ERROR ("Failed to open file: '%s' with error: '%s'",
60+
filename,
61+
bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf));
62+
goto fail;
63+
}
64+
65+
if (0 != fseek (file, 0, SEEK_END)) {
66+
MONGOC_ERROR ("Failed to seek in file: '%s' with error: '%s'",
67+
filename,
68+
bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf));
69+
goto fail;
70+
}
71+
72+
long file_len = ftell (file);
73+
if (file_len < 0) {
74+
MONGOC_ERROR ("Failed to get length of file: '%s' with error: '%s'",
75+
filename,
76+
bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf));
77+
goto fail;
78+
}
79+
80+
if (file_len > LONG_MAX - 1) {
81+
MONGOC_ERROR ("Failed to get length of file: '%s'. File too large", filename);
82+
goto fail;
83+
}
84+
85+
if (0 != fseek (file, 0, SEEK_SET)) {
86+
MONGOC_ERROR ("Failed to seek in file: '%s' with error: '%s'",
87+
filename,
88+
bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf));
89+
goto fail;
90+
}
91+
92+
// Read the whole file into one nul-terminated string:
93+
contents = (char *) bson_malloc ((size_t) file_len + 1u);
94+
contents[file_len] = '\0';
95+
if ((size_t) file_len != fread (contents, 1, file_len, file)) {
96+
if (feof (file)) {
97+
MONGOC_ERROR ("Unexpected EOF reading file: '%s'", filename);
98+
goto fail;
99+
} else {
100+
MONGOC_ERROR ("Failed to read file: '%s' with error: '%s'",
101+
filename,
102+
bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf));
103+
goto fail;
104+
}
105+
}
106+
if (out_len) {
107+
*out_len = (size_t) file_len;
108+
}
109+
110+
ok = true;
111+
fail:
112+
if (file) {
113+
fclose (file); // Ignore error.
114+
}
115+
if (!ok) {
116+
bson_free (contents);
117+
contents = NULL;
118+
}
119+
return contents;
120+
}
121+
44122

45123
PCCERT_CONTEXT
46124
mongoc_secure_channel_setup_certificate_from_file (const char *filename)
47125
{
48126
char *pem;
49-
FILE *file;
50127
bool ret = false;
51128
bool success;
52-
long pem_length;
129+
size_t pem_length;
53130
HCRYPTPROV provider;
54131
CERT_BLOB public_blob;
55132
const char *pem_public;
@@ -60,26 +137,11 @@ mongoc_secure_channel_setup_certificate_from_file (const char *filename)
60137
DWORD encrypted_private_len = 0;
61138
LPBYTE encrypted_private = NULL;
62139

63-
64-
file = fopen (filename, "rb");
65-
if (!file) {
66-
MONGOC_ERROR ("Couldn't open file '%s'", filename);
67-
return NULL;
68-
}
69-
70-
fseek (file, 0, SEEK_END);
71-
pem_length = ftell (file);
72-
fseek (file, 0, SEEK_SET);
73-
if (pem_length < 1 || length > LONG_MAX - 1) {
74-
MONGOC_ERROR ("Couldn't determine file size of '%s'", filename);
75-
return NULL;
140+
pem = read_file_and_null_terminate (filename, &pem_length);
141+
if (!pem) {
142+
goto fail;
76143
}
77144

78-
// Read the whole file into one nul-terminated string
79-
pem = (char *) bson_malloc0 ((size_t) pem_length + 1u);
80-
fread ((void *) pem, 1, pem_length, file);
81-
fclose (file);
82-
83145
pem_public = strstr (pem, "-----BEGIN CERTIFICATE-----");
84146
pem_private = strstr (pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----");
85147

@@ -258,39 +320,18 @@ bool
258320
mongoc_secure_channel_setup_ca (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt)
259321
{
260322
bool ok = false;
261-
FILE *file;
262-
long length;
263323
char *pem = NULL;
264324
const char *pem_key;
265325
HCERTSTORE cert_store = NULL;
266326
PCCERT_CONTEXT cert = NULL;
267327
DWORD encrypted_cert_len = 0;
268328
LPBYTE encrypted_cert = NULL;
269329

270-
file = fopen (opt->ca_file, "rb");
271-
if (!file) {
272-
MONGOC_ERROR ("Couldn't open file '%s'", opt->ca_file);
330+
pem = read_file_and_null_terminate (opt->ca_file, NULL);
331+
if (!pem) {
273332
return false;
274333
}
275334

276-
fseek (file, 0, SEEK_END);
277-
length = ftell (file);
278-
fseek (file, 0, SEEK_SET);
279-
if (length < 1 || length > LONG_MAX - 1) {
280-
MONGOC_WARNING ("Couldn't determine file size of '%s'", opt->ca_file);
281-
fclose (file);
282-
return false;
283-
}
284-
285-
// Read the whole file into one nul-terminated string
286-
pem = (char *) bson_malloc0 ((size_t) length + 1u);
287-
bool read_ok = (size_t) length == fread ((void *) pem, 1, length, file);
288-
fclose (file);
289-
if (!read_ok) {
290-
MONGOC_WARNING ("Couldn't read certificate file '%s'", opt->ca_file);
291-
goto fail;
292-
}
293-
294335
/* If we have private keys or other fuzz, seek to the good stuff */
295336
pem_key = strstr (pem, "-----BEGIN CERTIFICATE-----");
296337

0 commit comments

Comments
 (0)