1 /*
2 * ProFTPD: mod_sftp_sql -- SQL backend module for retrieving authorized keys
3 * Copyright (c) 2008-2016 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 *
24 * This is mod_sftp_sql, contrib software for proftpd 1.3.x and above.
25 * For more information contact TJ Saunders <tj@castaglia.org>.
26 */
27
28 #include "conf.h"
29 #include "privs.h"
30 #include "mod_sftp.h"
31 #include "mod_sql.h"
32
33 #define MOD_SFTP_SQL_VERSION "mod_sftp_sql/0.4"
34
35 module sftp_sql_module;
36
37 #define SFTP_SQL_BUFSZ 1024
38
39 struct sqlstore_key {
40 const char *subject;
41
42 /* Key data */
43 unsigned char *key_data;
44 uint32_t key_datalen;
45 };
46
47 struct sqlstore_data {
48 const char *select_query;
49 };
50
51 static const char *trace_channel = "ssh2";
52
sqlstore_cmd_create(pool * parent_pool,unsigned int argc,...)53 static cmd_rec *sqlstore_cmd_create(pool *parent_pool, unsigned int argc, ...) {
54 register unsigned int i = 0;
55 pool *cmd_pool = NULL;
56 cmd_rec *cmd = NULL;
57 va_list argp;
58
59 cmd_pool = make_sub_pool(parent_pool);
60 cmd = (cmd_rec *) pcalloc(cmd_pool, sizeof(cmd_rec));
61 cmd->pool = cmd_pool;
62
63 cmd->argc = argc;
64 cmd->argv = pcalloc(cmd->pool, argc * sizeof(void *));
65
66 /* Hmmm... */
67 cmd->tmp_pool = cmd->pool;
68
69 va_start(argp, argc);
70 for (i = 0; i < argc; i++) {
71 cmd->argv[i] = va_arg(argp, char *);
72 }
73 va_end(argp);
74
75 return cmd;
76 }
77
78 /* Given a blob of bytes retrieved from a single row, read that blob as if
79 * it were text, line by line.
80 */
sqlstore_getline(pool * p,char ** blob,size_t * bloblen)81 static char *sqlstore_getline(pool *p, char **blob, size_t *bloblen) {
82 char linebuf[SFTP_SQL_BUFSZ], *line = "", *data;
83 size_t datalen;
84
85 data = *blob;
86 datalen = *bloblen;
87
88 if (data == NULL ||
89 datalen == 0) {
90 errno = EOF;
91 return NULL;
92 }
93
94 while (data != NULL && datalen > 0) {
95 char *ptr;
96 size_t delimlen, linelen;
97 int have_line_continuation = FALSE;
98
99 pr_signals_handle();
100
101 if (datalen <= 2) {
102 line = pstrcat(p, line, data, NULL);
103
104 *blob = NULL;
105 *bloblen = 0;
106
107 return line;
108 }
109
110 /* Find the CRLF markers in the data. */
111 ptr = strstr(data, "\r\n");
112 if (ptr != NULL) {
113 delimlen = 1;
114
115 } else {
116 ptr = strstr(data, "\n");
117 if (ptr != NULL) {
118 delimlen = 0;
119 }
120 }
121
122 if (ptr == NULL) {
123 /* Just return the rest of the data. */
124 line = pstrcat(p, line, data, NULL);
125
126 *blob = NULL;
127 *bloblen = 0;
128
129 return line;
130 }
131
132 linelen = (ptr - data + 1);
133
134 if (linelen == 1) {
135 data += (delimlen + 1);
136 datalen -= (delimlen + 1);
137
138 continue;
139 }
140
141 /* Watch out for lines larger than our buffer. */
142 if (linelen > sizeof(linebuf)) {
143 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
144 "line of key data (%lu bytes) exceeds buffer size, truncating; "
145 "this WILL cause authentication failures", (unsigned long) linelen);
146 linelen = sizeof(linebuf);
147 }
148
149 memcpy(linebuf, data, linelen);
150 linebuf[linelen-1] = '\0';
151
152 data += (linelen + delimlen);
153 datalen -= (linelen + delimlen);
154
155 /* Check for continued lines. */
156 if (linelen >= 2 &&
157 linebuf[linelen-2] == '\\') {
158 linebuf[linelen-2] = '\0';
159 have_line_continuation = TRUE;
160 }
161
162 line = pstrcat(p, line, linebuf, NULL);
163 linelen = strlen(line);
164
165 if (have_line_continuation) {
166 continue;
167 }
168
169 ptr = strchr(line, ':');
170 if (ptr != NULL) {
171 unsigned int header_taglen, header_valuelen;
172
173 /* We have a header. Make sure the header tag is not longer than
174 * the specified length of 64 bytes, and that the header value is
175 * not longer than 1024 bytes.
176 */
177 header_taglen = ptr - line;
178 if (header_taglen > 64) {
179 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
180 "header tag too long (%u) in retrieved SQL data", header_taglen);
181 errno = EINVAL;
182 return NULL;
183 }
184
185 /* Header value starts at 2 after the ':' (one for the mandatory
186 * space character.
187 */
188 header_valuelen = linelen - (header_taglen + 2);
189 if (header_valuelen > 1024) {
190 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
191 "header value too long (%u) in retrieved SQL data", header_valuelen);
192 errno = EINVAL;
193 return NULL;
194 }
195 }
196
197 *blob = data;
198 *bloblen = datalen;
199
200 return line;
201 }
202
203 return NULL;
204 }
205
sqlstore_get_key_raw(pool * p,char ** blob,size_t * bloblen)206 static struct sqlstore_key *sqlstore_get_key_raw(pool *p, char **blob,
207 size_t *bloblen) {
208 char chunk[SFTP_SQL_BUFSZ], *data = NULL;
209 BIO *bio = NULL, *b64 = NULL, *bmem = NULL;
210 int chunklen;
211 long datalen = 0;
212 struct sqlstore_key *key = NULL;
213
214 bio = BIO_new(BIO_s_mem());
215
216 if (BIO_write(bio, (void *) *blob, *bloblen) < 0) {
217 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
218 "error buffering base64 data");
219 }
220
221 /* Add a base64 filter BIO, and read the data out, thus base64-decoding
222 * the key. Write the decoded data into another memory BIO.
223 */
224 b64 = BIO_new(BIO_f_base64());
225 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
226 bio = BIO_push(b64, bio);
227
228 bmem = BIO_new(BIO_s_mem());
229
230 memset(chunk, '\0', sizeof(chunk));
231 chunklen = BIO_read(bio, (void *) chunk, sizeof(chunk));
232
233 if (chunklen < 0 &&
234 !BIO_should_retry(bio)) {
235 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
236 "unable to base64-decode raw key data from database: %s",
237 sftp_crypto_get_errors());
238 BIO_free_all(bio);
239 BIO_free_all(bmem);
240
241 errno = EPERM;
242 return NULL;
243 }
244
245 while (chunklen > 0) {
246 pr_signals_handle();
247
248 if (BIO_write(bmem, (void *) chunk, chunklen) < 0) {
249 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
250 "error writing to memory BIO: %s", sftp_crypto_get_errors());
251 BIO_free_all(bio);
252 BIO_free_all(bmem);
253
254 errno = EPERM;
255 return NULL;
256 }
257
258 memset(chunk, '\0', sizeof(chunk));
259 chunklen = BIO_read(bio, (void *) chunk, sizeof(chunk));
260 }
261
262 datalen = BIO_get_mem_data(bmem, &data);
263
264 if (data != NULL &&
265 datalen > 0) {
266 key = pcalloc(p, sizeof(struct sqlstore_key));
267 key->key_data = pcalloc(p, datalen + 1);
268 key->key_datalen = datalen;
269 memcpy(key->key_data, data, datalen);
270
271 } else {
272 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
273 "error base64-decoding raw key data from database");
274 }
275
276 BIO_free_all(bio);
277 bio = NULL;
278
279 BIO_free_all(bmem);
280 return key;
281 }
282
sqlstore_get_key_rfc4716(pool * p,char ** blob,size_t * bloblen)283 static struct sqlstore_key *sqlstore_get_key_rfc4716(pool *p, char **blob,
284 size_t *bloblen) {
285 char *line;
286 BIO *bio = NULL;
287 struct sqlstore_key *key = NULL;
288 size_t begin_markerlen = 0, end_markerlen = 0;
289
290 line = sqlstore_getline(p, blob, bloblen);
291 while (line == NULL &&
292 errno == EINVAL) {
293 pr_signals_handle();
294 line = sqlstore_getline(p, blob, bloblen);
295 }
296
297 if (line == NULL) {
298 return NULL;
299 }
300
301 begin_markerlen = strlen(SFTP_SSH2_PUBKEY_BEGIN_MARKER);
302 end_markerlen = strlen(SFTP_SSH2_PUBKEY_END_MARKER);
303
304 while (line != NULL) {
305 pr_signals_handle();
306
307 if (key == NULL &&
308 strncmp(line, SFTP_SSH2_PUBKEY_BEGIN_MARKER, begin_markerlen) == 0) {
309 key = pcalloc(p, sizeof(struct sqlstore_key));
310 bio = BIO_new(BIO_s_mem());
311
312 } else if (key != NULL &&
313 strncmp(line, SFTP_SSH2_PUBKEY_END_MARKER, end_markerlen) == 0) {
314 if (bio != NULL) {
315 char chunk[SFTP_SQL_BUFSZ], *data = NULL;
316 BIO *b64 = NULL, *bmem = NULL;
317 int chunklen;
318 long datalen = 0;
319
320 /* Add a base64 filter BIO, and read the data out, thus base64-decoding
321 * the key. Write the decoded data into another memory BIO.
322 */
323 b64 = BIO_new(BIO_f_base64());
324 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
325 bio = BIO_push(b64, bio);
326
327 bmem = BIO_new(BIO_s_mem());
328
329 memset(chunk, '\0', sizeof(chunk));
330 chunklen = BIO_read(bio, (void *) chunk, sizeof(chunk));
331
332 if (chunklen < 0 &&
333 !BIO_should_retry(bio)) {
334 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
335 "unable to base64-decode RFC4716 key data from database: %s",
336 sftp_crypto_get_errors());
337 BIO_free_all(bio);
338 BIO_free_all(bmem);
339
340 errno = EPERM;
341 return NULL;
342 }
343
344 while (chunklen > 0) {
345 pr_signals_handle();
346
347 if (BIO_write(bmem, (void *) chunk, chunklen) < 0) {
348 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
349 "error writing to memory BIO: %s", sftp_crypto_get_errors());
350 BIO_free_all(bio);
351 BIO_free_all(bmem);
352
353 errno = EPERM;
354 return NULL;
355 }
356
357 memset(chunk, '\0', sizeof(chunk));
358 chunklen = BIO_read(bio, (void *) chunk, sizeof(chunk));
359 }
360
361 datalen = BIO_get_mem_data(bmem, &data);
362
363 if (data != NULL &&
364 datalen > 0) {
365 key = pcalloc(p, sizeof(struct sqlstore_key));
366 key->key_data = pcalloc(p, datalen + 1);
367 key->key_datalen = datalen;
368 memcpy(key->key_data, data, datalen);
369
370 } else {
371 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
372 "error base64-decoding RFC4716 key data from database");
373 }
374
375 BIO_free_all(bio);
376 bio = NULL;
377
378 BIO_free_all(bmem);
379 }
380
381 break;
382
383 } else {
384 if (key) {
385 if (strstr(line, ": ") != NULL) {
386 if (strncasecmp(line, "Subject: ", 9) == 0) {
387 key->subject = pstrdup(p, line + 9);
388 }
389
390 } else {
391 if (BIO_write(bio, line, strlen(line)) < 0) {
392 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
393 "error buffering base64 data");
394 }
395 }
396 }
397 }
398
399 line = sqlstore_getline(p, blob, bloblen);
400 while (line == NULL &&
401 errno == EINVAL) {
402 pr_signals_handle();
403 line = sqlstore_getline(p, blob, bloblen);
404 }
405 }
406
407 return key;
408 }
409
sqlstore_get_str(pool * p,char * str)410 static char *sqlstore_get_str(pool *p, char *str) {
411 cmdtable *cmdtab;
412 cmd_rec *cmd;
413 modret_t *res;
414
415 if (strlen(str) == 0)
416 return str;
417
418 /* Find the cmdtable for the sql_escapestr command. */
419 cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_escapestr", NULL, NULL, NULL);
420 if (cmdtab == NULL) {
421 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
422 "unable to find SQL hook symbol 'sql_escapestr'");
423 return str;
424 }
425
426 cmd = sqlstore_cmd_create(p, 1, pr_str_strip(p, str));
427
428 /* Call the handler. */
429 res = pr_module_call(cmdtab->m, cmdtab->handler, cmd);
430
431 /* Check the results. */
432 if (MODRET_ISERROR(res)) {
433 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
434 "error executing 'sql_escapestring'");
435 return str;
436 }
437
438 return res->data;
439 }
440
sqlstore_verify_key_raw(pool * p,struct sqlstore_data * store_data,int nrow,char * col_data,size_t col_datalen,unsigned char * key_data,uint32_t key_datalen)441 static int sqlstore_verify_key_raw(pool *p, struct sqlstore_data *store_data,
442 int nrow, char *col_data, size_t col_datalen, unsigned char *key_data,
443 uint32_t key_datalen) {
444 struct sqlstore_key *key;
445 int res;
446
447 key = sqlstore_get_key_raw(p, &col_data, &col_datalen);
448 if (key == NULL) {
449 pr_trace_msg(trace_channel, 10,
450 "unable to parse data (row %u) as raw data", nrow+1);
451 return -1;
452 }
453
454 res = sftp_keys_compare_keys(p, key_data, key_datalen, key->key_data,
455 key->key_datalen);
456 if (res < 0) {
457 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
458 "error comparing client-sent host key with SQL data (row %u) from "
459 "SQLNamedQuery '%s': %s", nrow+1, store_data->select_query,
460 strerror(errno));
461
462 } else if (res == FALSE) {
463 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
464 "client-sent host key does not match SQL data (row %u) from "
465 "SQLNamedQuery '%s'", nrow+1, store_data->select_query);
466 res = -1;
467
468 } else {
469 res = 0;
470 }
471
472 return res;
473 }
474
sqlstore_verify_key_rfc4716(pool * p,struct sqlstore_data * store_data,int nrow,char * col_data,size_t col_datalen,unsigned char * key_data,uint32_t key_datalen)475 static int sqlstore_verify_key_rfc4716(pool *p,
476 struct sqlstore_data *store_data, int nrow, char *col_data,
477 size_t col_datalen, unsigned char *key_data, uint32_t key_datalen) {
478 struct sqlstore_key *key;
479 int res;
480
481 key = sqlstore_get_key_rfc4716(p, &col_data, &col_datalen);
482 while (key != NULL) {
483 pr_signals_handle();
484
485 res = sftp_keys_compare_keys(p, key_data, key_datalen, key->key_data,
486 key->key_datalen);
487 if (res < 0) {
488 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
489 "error comparing client-sent key with SQL data (row %u) from "
490 "SQLNamedQuery '%s': %s", nrow+1, store_data->select_query,
491 strerror(errno));
492 key = sqlstore_get_key_rfc4716(p, &col_data, &col_datalen);
493 continue;
494
495 } else if (res == FALSE) {
496 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
497 "client-sent key does not match SQL data (row %u) from "
498 "SQLNamedQuery '%s'", nrow+1, store_data->select_query);
499 key = sqlstore_get_key_rfc4716(p, &col_data, &col_datalen);
500 continue;
501 }
502
503 return 0;
504 }
505
506 return -1;
507 }
508
sqlstore_verify_host_key(sftp_keystore_t * store,pool * p,const char * user,const char * host_fqdn,const char * host_user,unsigned char * key_data,uint32_t key_datalen)509 static int sqlstore_verify_host_key(sftp_keystore_t *store, pool *p,
510 const char *user, const char *host_fqdn, const char *host_user,
511 unsigned char *key_data, uint32_t key_datalen) {
512 register unsigned int i;
513 struct sqlstore_data *store_data;
514 pool *tmp_pool;
515 cmdtable *sql_cmdtab;
516 cmd_rec *sql_cmd;
517 modret_t *sql_res;
518 array_header *sql_data;
519 char **values;
520 int res;
521
522 store_data = store->keystore_data;
523
524 /* Find the cmdtable for the sql_lookup command. */
525 sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_lookup", NULL, NULL,
526 NULL);
527 if (sql_cmdtab == NULL) {
528 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
529 "unable to find SQL hook symbol 'sql_lookup'");
530 errno = EPERM;
531 return -1;
532 }
533
534 tmp_pool = make_sub_pool(store->keystore_pool);
535
536 /* Prepare the SELECT query. */
537 sql_cmd = sqlstore_cmd_create(tmp_pool, 3, "sql_lookup",
538 store_data->select_query, sqlstore_get_str(tmp_pool, (char *) host_fqdn));
539
540 /* Call the handler. */
541 sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
542 if (sql_res == NULL ||
543 MODRET_ISERROR(sql_res)) {
544 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
545 "error processing SQLNamedQuery '%s'", store_data->select_query);
546 destroy_pool(tmp_pool);
547
548 errno = EPERM;
549 return -1;
550 }
551
552 sql_data = (array_header *) sql_res->data;
553
554 if (sql_data->nelts == 0) {
555 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
556 "SQLNamedQuery '%s' returned zero results", store_data->select_query);
557 destroy_pool(tmp_pool);
558 errno = ENOENT;
559 return -1;
560
561 } else {
562 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
563 "SQLNamedQuery '%s' returned %d %s", store_data->select_query,
564 sql_data->nelts, sql_data->nelts != 1 ? "rows" : "row");
565 }
566
567 values = (char **) sql_data->elts;
568 for (i = 0; i < sql_data->nelts; i++) {
569 char *col_data;
570 size_t col_datalen;
571
572 pr_signals_handle();
573
574 col_data = values[i];
575 col_datalen = strlen(values[i]);
576
577 res = sqlstore_verify_key_rfc4716(p, store_data, i, col_data, col_datalen,
578 key_data, key_datalen);
579 if (res == 0) {
580 pr_trace_msg(trace_channel, 10, "found matching RFC4716 public key "
581 "(row %u) for host '%s' using SQLNamedQuery '%s'", i+1, host_fqdn,
582 store_data->select_query);
583 destroy_pool(tmp_pool);
584 return 0;
585 }
586
587 res = sqlstore_verify_key_raw(p, store_data, i, col_data, col_datalen,
588 key_data, key_datalen);
589 if (res == 0) {
590 pr_trace_msg(trace_channel, 10, "found matching public key (row %u) for "
591 "host '%s' using SQLNamedQuery '%s'", i+1, host_fqdn,
592 store_data->select_query);
593 destroy_pool(tmp_pool);
594 return 0;
595 }
596 }
597
598 destroy_pool(tmp_pool);
599 errno = ENOENT;
600 return -1;
601 }
602
sqlstore_verify_user_key(sftp_keystore_t * store,pool * p,const char * user,unsigned char * key_data,uint32_t key_datalen)603 static int sqlstore_verify_user_key(sftp_keystore_t *store, pool *p,
604 const char *user, unsigned char *key_data, uint32_t key_datalen) {
605 register unsigned int i;
606 struct sqlstore_data *store_data;
607 pool *tmp_pool;
608 cmdtable *sql_cmdtab;
609 cmd_rec *sql_cmd;
610 modret_t *sql_res;
611 array_header *sql_data;
612 char **values;
613
614 store_data = store->keystore_data;
615
616 /* Find the cmdtable for the sql_lookup command. */
617 sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_lookup", NULL, NULL,
618 NULL);
619 if (sql_cmdtab == NULL) {
620 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
621 "unable to find SQL hook symbol 'sql_lookup'");
622 errno = EPERM;
623 return -1;
624 }
625
626 tmp_pool = make_sub_pool(store->keystore_pool);
627
628 /* Prepare the SELECT query. */
629 sql_cmd = sqlstore_cmd_create(tmp_pool, 3, "sql_lookup",
630 store_data->select_query, sqlstore_get_str(tmp_pool, (char *) user));
631
632 /* Call the handler. */
633 sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
634 if (sql_res == NULL ||
635 MODRET_ISERROR(sql_res)) {
636 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
637 "error processing SQLNamedQuery '%s'", store_data->select_query);
638 destroy_pool(tmp_pool);
639
640 errno = EPERM;
641 return -1;
642 }
643
644 sql_data = (array_header *) sql_res->data;
645
646 if (sql_data->nelts == 0) {
647 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
648 "SQLNamedQuery '%s' returned zero results", store_data->select_query);
649 destroy_pool(tmp_pool);
650 errno = ENOENT;
651 return -1;
652 }
653
654 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
655 "SQLNamedQuery '%s' returned %d %s", store_data->select_query,
656 sql_data->nelts, sql_data->nelts != 1 ? "rows" : "row");
657
658 values = (char **) sql_data->elts;
659 for (i = 0; i < sql_data->nelts; i++) {
660 int res;
661 char *col_data;
662 size_t col_datalen;
663
664 pr_signals_handle();
665
666 col_data = values[i];
667 col_datalen = strlen(values[i]);
668
669 res = sqlstore_verify_key_rfc4716(p, store_data, i, col_data, col_datalen,
670 key_data, key_datalen);
671 if (res == 0) {
672 pr_trace_msg(trace_channel, 10, "found matching RFC4716 public key "
673 "(row %u) for user '%s' using SQLNamedQuery '%s'", i+1, user,
674 store_data->select_query);
675 destroy_pool(tmp_pool);
676 return 0;
677 }
678
679 res = sqlstore_verify_key_raw(p, store_data, i, col_data, col_datalen,
680 key_data, key_datalen);
681 if (res == 0) {
682 pr_trace_msg(trace_channel, 10, "found matching public key (row %u) for "
683 "user '%s' using SQLNamedQuery '%s'", i+1, user,
684 store_data->select_query);
685 destroy_pool(tmp_pool);
686 return 0;
687 }
688 }
689
690 destroy_pool(tmp_pool);
691 errno = ENOENT;
692 return -1;
693 }
694
sqlstore_close(sftp_keystore_t * store)695 static int sqlstore_close(sftp_keystore_t *store) {
696 /* Nothing really to do here. */
697 return 0;
698 }
699
sqlstore_open(pool * parent_pool,int requested_key_type,const char * store_info,const char * user)700 static sftp_keystore_t *sqlstore_open(pool *parent_pool,
701 int requested_key_type, const char *store_info, const char *user) {
702 sftp_keystore_t *store;
703 pool *sqlstore_pool, *tmp_pool;
704 struct sqlstore_data *store_data;
705 char *named_query, *select_query, *ptr;
706 config_rec *c;
707
708 tmp_pool = make_sub_pool(parent_pool);
709
710 sqlstore_pool = make_sub_pool(parent_pool);
711 pr_pool_tag(sqlstore_pool, "SFTP SQL-based Keystore Pool");
712
713 store = pcalloc(sqlstore_pool, sizeof(sftp_keystore_t));
714 store->keystore_pool = sqlstore_pool;
715 store->store_ktypes = requested_key_type;
716
717 switch (requested_key_type) {
718 case SFTP_SSH2_HOST_KEY_STORE:
719 store->verify_host_key = sqlstore_verify_host_key;
720 break;
721
722 case SFTP_SSH2_USER_KEY_STORE:
723 store->verify_user_key = sqlstore_verify_user_key;
724 break;
725 }
726
727 store->store_close = sqlstore_close;
728
729 /* Parse the SELECT query name out of the store_info string:
730 *
731 * "/<select-named-query"
732 */
733 ptr = strchr(store_info, '/');
734 if (ptr == NULL) {
735 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_SQL_VERSION,
736 "badly formatted store info '%s'", store_info);
737 destroy_pool(tmp_pool);
738
739 errno = EINVAL;
740 return NULL;
741 }
742
743 ptr++;
744 select_query = pstrdup(sqlstore_pool, ptr);
745
746 /* Verify that the named query has indeed been configured. This is based
747 * on how mod_sql creates its config_rec names.
748 */
749 named_query = pstrcat(tmp_pool, "SQLNamedQuery_", select_query, NULL);
750
751 c = find_config(main_server->conf, CONF_PARAM, named_query, FALSE);
752 if (c == NULL) {
753 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
754 "unable to resolve SQLNamedQuery '%s'", select_query);
755 destroy_pool(tmp_pool);
756
757 errno = EINVAL;
758 return NULL;
759 }
760
761 store_data = pcalloc(sqlstore_pool, sizeof(struct sqlstore_data));
762 store->keystore_data = store_data;
763 store_data->select_query = pstrdup(sqlstore_pool, select_query);
764
765 destroy_pool(tmp_pool);
766 return store;
767 }
768
769 /* Event Handlers
770 */
771
772 #if defined(PR_SHARED_MODULE)
sftpsql_mod_unload_ev(const void * event_data,void * user_data)773 static void sftpsql_mod_unload_ev(const void *event_data, void *user_data) {
774 if (strcmp("mod_sftp_sql.c", (const char *) event_data) == 0) {
775 /* XXX any further cleanup here */
776
777 sftp_keystore_unregister_store("sql",
778 SFTP_SSH2_HOST_KEY_STORE|SFTP_SSH2_USER_KEY_STORE);
779 pr_event_unregister(&sftp_sql_module, NULL, NULL);
780 }
781 }
782 #endif /* !PR_SHARED_MODULE */
783
784 /* Initialization functions
785 */
786
sftpsql_init(void)787 static int sftpsql_init(void) {
788
789 sftp_keystore_register_store("sql", sqlstore_open,
790 SFTP_SSH2_HOST_KEY_STORE|SFTP_SSH2_USER_KEY_STORE);
791
792 #if defined(PR_SHARED_MODULE)
793 pr_event_register(&sftp_sql_module, "core.module-unload",
794 sftpsql_mod_unload_ev, NULL);
795 #endif /* !PR_SHARED_MODULE */
796
797 return 0;
798 }
799
800 module sftp_sql_module = {
801 NULL, NULL,
802
803 /* Module API version 2.0 */
804 0x20,
805
806 /* Module name */
807 "sftp_sql",
808
809 /* Module configuration handler table */
810 NULL,
811
812 /* Module command handler table */
813 NULL,
814
815 /* Module authentication handler table */
816 NULL,
817
818 /* Module initialization function */
819 sftpsql_init,
820
821 /* Session initialization function */
822 NULL,
823
824 /* Module version */
825 MOD_SFTP_SQL_VERSION
826 };
827