Skip to content

Commit 0aaf0d0

Browse files
authored
Be more defensive in native extension. (#10)
* Be more defensive in native extension. - Explicitly reserve a byte for null terminator in strings - Only close the connection being worked on with sasl_dispose rather than all of them * Add some comments * Review feedback
1 parent c7770f1 commit 0aaf0d0

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

ext/mongo_kerberos/mongo_kerberos_native.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@
1818

1919
static void mongo_sasl_conn_free(void* data) {
2020
sasl_conn_t *conn = (sasl_conn_t*) data;
21-
// Ideally we would use sasl_client_done() but that's only available as of cyrus sasl 2.1.25
22-
if(conn) sasl_done();
21+
if (conn) {
22+
sasl_dispose(&conn);
23+
/* We do not set connection to NULL in the Ruby object. */
24+
/* This is probably fine because this method is supposed to be called */
25+
/* when the Ruby object is being garbage collected. */
26+
/* Plus, we don't have the Ruby object reference here to do anything */
27+
/* with it. */
28+
}
2329
}
2430

2531
static sasl_conn_t* mongo_sasl_context(VALUE self) {
@@ -104,7 +110,14 @@ static VALUE initialize_challenge(VALUE self) {
104110
}
105111

106112
context = Data_Wrap_Struct(rb_cObject, NULL, mongo_sasl_conn_free, conn);
113+
/* I'm guessing ruby raises on out of memory condition rather than */
114+
/* returns NULL, hence no error checking is needed here? */
115+
116+
/* from now on context owns conn */
117+
/* since mongo_sasl_conn_free cleans up conn, we should NOT call */
118+
/* sasl_dispose any more in this function. */
107119
rb_iv_set(self, "@context", context);
120+
RB_GC_GUARD(context);
108121

109122
result = sasl_client_start(conn, mechanism_list, NULL, &raw_payload, &raw_payload_len, &mechanism_selected);
110123
if (is_sasl_failure(result)) {
@@ -115,7 +128,9 @@ static VALUE initialize_challenge(VALUE self) {
115128
return Qfalse;
116129
}
117130

118-
result = sasl_encode64(raw_payload, raw_payload_len, encoded_payload, sizeof(encoded_payload), &encoded_payload_len);
131+
/* cyrus-sasl considers `outmax` (fourth argument) to include the null */
132+
/* terminator, but this is not documented. Be defensive and exclude it. */
133+
result = sasl_encode64(raw_payload, raw_payload_len, encoded_payload, sizeof(encoded_payload)-1, &encoded_payload_len);
119134
if (is_sasl_failure(result)) {
120135
return Qfalse;
121136
}
@@ -135,17 +150,17 @@ static VALUE evaluate_challenge(VALUE self, VALUE rb_payload) {
135150
step_payload = RSTRING_PTR(rb_payload);
136151
step_payload_len = (int)RSTRING_LEN(rb_payload);
137152

138-
result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload), &base_payload_len);
153+
result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload)-1, &base_payload_len);
139154
if (is_sasl_failure(result)) {
140155
return Qfalse;
141156
}
142157

143158
result = sasl_client_step(conn, base_payload, base_payload_len, NULL, &out, &outlen);
144159
if (is_sasl_failure(result)) {
145-
return Qfalse;
160+
return Qfalse;
146161
}
147162

148-
result = sasl_encode64(out, outlen, payload, sizeof(payload), &payload_len);
163+
result = sasl_encode64(out, outlen, payload, sizeof(payload)-1, &payload_len);
149164
if (is_sasl_failure(result)) {
150165
return Qfalse;
151166
}

0 commit comments

Comments
 (0)