log_pgsql.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. #include <config.h>
  2. /* PostgreSQL backend, by Cindy Marasco <cindy at getaclue.org> */
  3. #ifdef WITH_PGSQL
  4. # include "ftpd.h"
  5. # include "parser.h"
  6. # include "log_pgsql_p.h"
  7. # include "log_pgsql.h"
  8. # include "messages.h"
  9. # include "crypto.h"
  10. # include "alt_arc4random.h"
  11. # include "utils.h"
  12. # ifdef HAVE_LIBSODIUM
  13. # include <sodium.h>
  14. # endif
  15. # ifdef WITH_DMALLOC
  16. # include <dmalloc.h>
  17. # endif
  18. static int pw_pgsql_validate_name(const char *name)
  19. {
  20. if (name == NULL || *name == 0) {
  21. return -1;
  22. }
  23. do {
  24. if ((*name >= 'a' && *name <= 'z') ||
  25. (*name >= 'A' && *name <= 'Z') ||
  26. (*name >= '0' && *name <= '9') ||
  27. *name == ' ' || *name == '-' ||
  28. *name == '_' || *name == '\'' || *name == '.' ||
  29. *name == ':' || *name == '@' || *name == '+') {
  30. /* God bless the Ruby 'unless' keyword */
  31. } else {
  32. return -1;
  33. }
  34. name++;
  35. } while (*name != 0);
  36. return 0;
  37. }
  38. static char *pw_pgsql_escape_string(PGconn * const id_sql_server,
  39. const char *from)
  40. {
  41. size_t from_len;
  42. size_t to_len;
  43. char *to;
  44. size_t tolen;
  45. unsigned int t;
  46. unsigned char t1, t2;
  47. int error;
  48. if (from == NULL) {
  49. return NULL;
  50. }
  51. from_len = strlen(from);
  52. to_len = from_len * 2U + (size_t) 1U;
  53. if ((to = malloc(to_len + (size_t) 2U)) == NULL) {
  54. return NULL;
  55. }
  56. t = zrand();
  57. t1 = t & 0xff;
  58. t2 = (t >> 8) & 0xff;
  59. to[to_len] = (char) t1;
  60. to[to_len + 1] = (char) t2;
  61. /*
  62. * I really hate giving a buffer without any size to a 3rd party function.
  63. * The "to" buffer is allocated on the heap, not on the stack, if
  64. * PQescapeStringConn() is buggy, the stack shouldn't be already
  65. * smashed at this point, but data from other malloc can be corrupted and
  66. * bad things can happen. It make sense to wipe this area as soon as
  67. * possible instead of doing anything with the heap. We'll end up with
  68. * a segmentation violation, but without any possible exploit.
  69. */
  70. tolen = PQescapeStringConn(id_sql_server, to, from, from_len, &error);
  71. if (tolen >= to_len ||
  72. (unsigned char) to[to_len] != t1 ||
  73. (unsigned char) to[to_len + 1] != t2) {
  74. for (;;) {
  75. *to++ = 0;
  76. }
  77. }
  78. to[tolen] = 0;
  79. if (error != 0) {
  80. return NULL;
  81. }
  82. return to;
  83. }
  84. /*
  85. * Substitute digraphs for SQL requests.
  86. * orig_str is the original string, from the configuration file
  87. * full of \L, \I, \P, \R and \D.
  88. * query is a buffer to handle the result.
  89. * query_len is the size of the buffer.
  90. * returns the buffer @ if successful, NULL otherwise. -frank.
  91. */
  92. static char *sqlsubst(const char *orig_str, char * const query,
  93. size_t query_len, const char * const user,
  94. const char * const ip, const char * const port,
  95. const char * const peer_ip,
  96. const char * const decimal_ip)
  97. {
  98. char *query_pnt = query;
  99. const char *orig_str_scan = orig_str;
  100. const size_t user_len = (user == NULL ? (size_t) 0U : strlen(user));
  101. const size_t ip_len = (ip == NULL ? (size_t) 0U : strlen(ip));
  102. const size_t port_len = (port == NULL ? (size_t) 0U : strlen(port));
  103. const size_t peer_ip_len = (peer_ip == NULL ? (size_t) 0U : strlen(peer_ip));
  104. const size_t decimal_ip_len = (decimal_ip == NULL ? (size_t) 0U : strlen(decimal_ip));
  105. while (*orig_str_scan != 0) {
  106. if (*orig_str_scan == '\\' && orig_str_scan[1] != 0) {
  107. orig_str_scan++;
  108. switch(tolower((unsigned char) *orig_str_scan)) {
  109. case 'l' :
  110. if (user_len >= query_len) {
  111. return NULL;
  112. }
  113. if (user_len <= (size_t) 0U) {
  114. goto nextone;
  115. }
  116. memcpy(query_pnt, user, user_len);
  117. query_pnt += user_len;
  118. query_len -= user_len;
  119. goto nextone;
  120. case 'i' :
  121. if (ip_len >= query_len) {
  122. return NULL;
  123. }
  124. if (ip_len <= (size_t) 0U) {
  125. goto nextone;
  126. }
  127. memcpy(query_pnt, ip, ip_len);
  128. query_pnt += ip_len;
  129. query_len -= ip_len;
  130. goto nextone;
  131. case 'p' :
  132. if (port_len >= query_len) {
  133. return NULL;
  134. }
  135. if (port_len <= (size_t) 0U) {
  136. goto nextone;
  137. }
  138. memcpy(query_pnt, port, port_len);
  139. query_pnt += port_len;
  140. query_len -= port_len;
  141. goto nextone;
  142. case 'r' :
  143. if (peer_ip_len >= query_len) {
  144. return NULL;
  145. }
  146. if (peer_ip_len <= (size_t) 0U) {
  147. goto nextone;
  148. }
  149. memcpy(query_pnt, peer_ip, peer_ip_len);
  150. query_pnt += peer_ip_len;
  151. query_len -= peer_ip_len;
  152. goto nextone;
  153. case 'd' :
  154. if (decimal_ip_len >= query_len) {
  155. return NULL;
  156. }
  157. if (decimal_ip_len <= (size_t) 0U) {
  158. goto nextone;
  159. }
  160. memcpy(query_pnt, decimal_ip, decimal_ip_len);
  161. query_pnt += decimal_ip_len;
  162. query_len -= decimal_ip_len;
  163. goto nextone;
  164. default :
  165. if (--query_len <= (size_t) 0U) {
  166. return NULL;
  167. }
  168. *query_pnt++ = '\\';
  169. }
  170. }
  171. if (ISCTRLCODE(*orig_str_scan)) {
  172. goto nextone;
  173. }
  174. if (--query_len <= (size_t) 0U) {
  175. return NULL;
  176. }
  177. *query_pnt++ = *orig_str_scan;
  178. nextone:
  179. orig_str_scan++;
  180. }
  181. *query_pnt = 0;
  182. return query;
  183. }
  184. static size_t pw_pgsql_escape_conninfo_(char * const to,
  185. const char * const from,
  186. const size_t length)
  187. {
  188. const char *source = from;
  189. char *target = to;
  190. size_t remaining = length;
  191. while (remaining > (size_t) 0U) {
  192. switch (*source) {
  193. case 0:
  194. remaining = (size_t) 1U;
  195. break;
  196. case '\r':
  197. *target++ = '\\';
  198. *target++ = 'r';
  199. break;
  200. case '\n':
  201. *target++ = '\\';
  202. *target++ = 'n';
  203. break;
  204. case '\b':
  205. *target++ = '\\';
  206. *target++ = 'b';
  207. break;
  208. case '\'':
  209. *target++ = '\'';
  210. *target++ = '\'';
  211. break;
  212. case '\\':
  213. case '"':
  214. *target++ = '\\';
  215. default:
  216. *target++ = *source;
  217. }
  218. source++;
  219. remaining--;
  220. }
  221. *target = 0;
  222. return (size_t) (target - to);
  223. }
  224. static char *pw_pgsql_escape_conninfo(const char *from)
  225. {
  226. size_t from_len;
  227. size_t to_len;
  228. char *to;
  229. size_t tolen;
  230. if (from == NULL) {
  231. return NULL;
  232. }
  233. from_len = strlen(from);
  234. to_len = from_len * 2U + (size_t) 1U;
  235. if ((to = malloc(to_len)) == NULL) {
  236. return NULL;
  237. }
  238. tolen = pw_pgsql_escape_conninfo_(to, from, from_len);
  239. if (tolen >= to_len) {
  240. for (;;) {
  241. *to++ = 0;
  242. }
  243. }
  244. to[tolen] = 0;
  245. return to;
  246. }
  247. static int pw_pgsql_connect(PGconn ** const id_sql_server)
  248. {
  249. char *conninfo = NULL;
  250. size_t sizeof_conninfo;
  251. char *escaped_server = NULL;
  252. char *escaped_db = NULL;
  253. char *escaped_user = NULL;
  254. char *escaped_pw = NULL;
  255. int ret = -1;
  256. *id_sql_server = NULL;
  257. if ((escaped_server = pw_pgsql_escape_conninfo(server)) == NULL ||
  258. (escaped_db = pw_pgsql_escape_conninfo(db)) == NULL ||
  259. (escaped_user = pw_pgsql_escape_conninfo(user)) == NULL ||
  260. (escaped_pw = pw_pgsql_escape_conninfo(pw)) == NULL) {
  261. goto bye;
  262. }
  263. #define PGSQL_CONNECT_FMTSTRING \
  264. "host='%s' port='%d' dbname='%s' user='%s' password='%s'"
  265. sizeof_conninfo = sizeof PGSQL_CONNECT_FMTSTRING +
  266. strlen(escaped_server) + (size_t) 5U + strlen(escaped_db) +
  267. strlen(escaped_user) + strlen(escaped_pw);
  268. if ((conninfo = malloc(sizeof_conninfo)) == NULL) {
  269. goto bye;
  270. }
  271. if (SNCHECK(snprintf(conninfo, sizeof_conninfo,
  272. PGSQL_CONNECT_FMTSTRING,
  273. server, port, db, user, pw), sizeof_conninfo)) {
  274. goto bye;
  275. }
  276. if ((*id_sql_server = PQconnectdb(conninfo)) == NULL ||
  277. PQstatus(*id_sql_server) == CONNECTION_BAD) {
  278. if (server_down == 0) {
  279. server_down++;
  280. logfile(LOG_ERR, MSG_SQL_DOWN);
  281. }
  282. goto bye;
  283. }
  284. server_down = 0;
  285. ret = 0;
  286. bye:
  287. free(conninfo);
  288. free(escaped_server);
  289. free(escaped_db);
  290. free(escaped_user);
  291. free(escaped_pw);
  292. return ret;
  293. }
  294. static int pw_pgsql_simplequery(PGconn * const id_sql_server,
  295. const char * const query)
  296. {
  297. PGresult *result;
  298. if ((result = PQexec(id_sql_server, query)) == NULL) {
  299. return -1;
  300. }
  301. if (PQresultStatus(result) != PGRES_COMMAND_OK) {
  302. PQclear(result);
  303. return -1;
  304. }
  305. PQclear(result);
  306. return 0;
  307. }
  308. static char *pw_pgsql_getquery(PGconn * const id_sql_server,
  309. const char * const orig_query,
  310. const char * const account,
  311. const char * const ip,
  312. const char * const port,
  313. const char * const peer_ip,
  314. const char * const decimal_ip)
  315. {
  316. PGresult *qresult = NULL;
  317. size_t length;
  318. char *answer = NULL;
  319. char query[PGSQL_MAX_REQUEST_LENGTH];
  320. if (orig_query == NULL || *orig_query == 0) {
  321. goto bye;
  322. }
  323. if (sqlsubst(orig_query, query, sizeof query,
  324. account, ip, port, peer_ip, decimal_ip) == NULL) {
  325. goto bye;
  326. }
  327. if ((qresult = PQexec(id_sql_server, query)) == NULL) {
  328. logfile(LOG_WARNING, MSG_SQL_WRONG_PARMS " : [%s]", query);
  329. goto bye;
  330. }
  331. if (PQresultStatus(qresult) != PGRES_TUPLES_OK ||
  332. PQnfields(qresult) != 1 ||
  333. PQntuples(qresult) != 1 ||
  334. PQgetisnull(qresult, 0, 0)) {
  335. goto bye;
  336. }
  337. if ((length = (size_t) PQgetlength(qresult, 0, 0) + (size_t) 1U)
  338. <= (size_t) 1U || (answer = malloc(length)) == NULL) {
  339. goto bye;
  340. }
  341. strncpy(answer, PQgetvalue(qresult, 0, 0), length - (size_t) 1U);
  342. answer[length - (size_t) 1U] = 0;
  343. bye:
  344. if (qresult != NULL) {
  345. PQclear(qresult);
  346. }
  347. return answer;
  348. }
  349. void pw_pgsql_check(AuthResult * const result,
  350. const char *account, const char *password,
  351. const struct sockaddr_storage * const sa,
  352. const struct sockaddr_storage * const peer)
  353. {
  354. PGconn *id_sql_server = NULL;
  355. const char *spwd = NULL; /* stored password */
  356. const char *uid = sql_default_uid; /* stored system login/uid */
  357. const char *gid = sql_default_gid; /* stored system group/gid */
  358. const char *dir = NULL; /* stored home directory */
  359. #ifdef QUOTAS
  360. const char *sqta_fs = NULL; /* stored quota files */
  361. const char *sqta_sz = NULL; /* stored quota size */
  362. #endif
  363. #ifdef RATIOS
  364. const char *ratio_ul = NULL; /* stored ratio UL */
  365. const char *ratio_dl = NULL; /* stored ratio DL */
  366. #endif
  367. #ifdef THROTTLING
  368. const char *bandwidth_ul = NULL; /* stored bandwidth UL */
  369. const char *bandwidth_dl = NULL; /* stored bandwidth DL */
  370. #endif
  371. char *escaped_account = NULL;
  372. char *escaped_ip = NULL;
  373. char *escaped_port = NULL;
  374. char *escaped_peer_ip = NULL;
  375. char *escaped_decimal_ip = NULL;
  376. char *scrambled_password = NULL;
  377. int committed = 1;
  378. int crypto_argon2 = 0, crypto_scrypt = 0, crypto_crypt = 0, crypto_md5 = 0,
  379. crypto_sha1 = 0, crypto_plain = 0;
  380. unsigned long decimal_ip_num = 0UL;
  381. char decimal_ip[42];
  382. char hbuf[NI_MAXHOST];
  383. char pbuf[NI_MAXSERV];
  384. char phbuf[NI_MAXHOST];
  385. result->auth_ok = 0;
  386. if (pw_pgsql_validate_name(account) != 0) {
  387. goto bye;
  388. }
  389. if (getnameinfo((const struct sockaddr *) sa, STORAGE_LEN(*sa),
  390. hbuf, sizeof hbuf, pbuf, sizeof pbuf,
  391. NI_NUMERICHOST | NI_NUMERICSERV) != 0 ||
  392. getnameinfo((const struct sockaddr *) peer, STORAGE_LEN(*peer),
  393. phbuf, sizeof phbuf, NULL, (size_t) 0U,
  394. NI_NUMERICHOST) != 0) {
  395. goto bye;
  396. }
  397. *decimal_ip = 0;
  398. if (STORAGE_FAMILY(*peer) == AF_INET) {
  399. const unsigned char *decimal_ip_raw =
  400. (const unsigned char *) &(STORAGE_SIN_ADDR(*peer));
  401. decimal_ip_num = ((unsigned long) decimal_ip_raw[0] << 24) |
  402. ((unsigned long) decimal_ip_raw[1] << 16) |
  403. (decimal_ip_raw[2] << 8) | decimal_ip_raw[3];
  404. if (SNCHECK(snprintf(decimal_ip, sizeof decimal_ip,
  405. "%lu", decimal_ip_num), sizeof decimal_ip)) {
  406. goto bye;
  407. }
  408. }
  409. if (pw_pgsql_connect(&id_sql_server) != 0) {
  410. goto bye;
  411. }
  412. if ((escaped_account =
  413. pw_pgsql_escape_string(id_sql_server, account)) == NULL) {
  414. goto bye;
  415. }
  416. if ((escaped_ip =
  417. pw_pgsql_escape_string(id_sql_server, hbuf)) == NULL) {
  418. goto bye;
  419. }
  420. if ((escaped_port =
  421. pw_pgsql_escape_string(id_sql_server, pbuf)) == NULL) {
  422. goto bye;
  423. }
  424. if ((escaped_peer_ip =
  425. pw_pgsql_escape_string(id_sql_server, phbuf)) == NULL) {
  426. goto bye;
  427. }
  428. if ((escaped_decimal_ip =
  429. pw_pgsql_escape_string(id_sql_server, decimal_ip)) == NULL) {
  430. goto bye;
  431. }
  432. if (pw_pgsql_simplequery(id_sql_server, PGSQL_TRANSACTION_START) == 0) {
  433. committed = 0;
  434. }
  435. if ((spwd = pw_pgsql_getquery(id_sql_server, sqlreq_getpw,
  436. escaped_account, escaped_ip,
  437. escaped_port, escaped_peer_ip,
  438. escaped_decimal_ip)) == NULL) {
  439. goto bye;
  440. }
  441. if (uid == NULL) {
  442. uid = pw_pgsql_getquery(id_sql_server, sqlreq_getuid,
  443. escaped_account, escaped_ip,
  444. escaped_port, escaped_peer_ip,
  445. escaped_decimal_ip);
  446. }
  447. if (uid == NULL) {
  448. goto bye;
  449. }
  450. if (gid == NULL) {
  451. gid = pw_pgsql_getquery(id_sql_server, sqlreq_getgid,
  452. escaped_account, escaped_ip,
  453. escaped_port, escaped_peer_ip,
  454. escaped_decimal_ip);
  455. }
  456. if (gid == NULL) {
  457. goto bye;
  458. }
  459. if ((dir = pw_pgsql_getquery(id_sql_server, sqlreq_getdir,
  460. escaped_account, escaped_ip,
  461. escaped_port, escaped_peer_ip,
  462. escaped_decimal_ip)) == NULL) {
  463. goto bye;
  464. }
  465. result->auth_ok--; /* -1 */
  466. if (strcasecmp(crypto, PASSWD_SQL_ANY) == 0) {
  467. crypto_argon2++;
  468. crypto_scrypt++;
  469. crypto_crypt++;
  470. crypto_md5++;
  471. crypto_sha1++;
  472. } else if (strcasecmp(crypto, PASSWD_SQL_ARGON2) == 0) {
  473. crypto_argon2++;
  474. } else if (strcasecmp(crypto, PASSWD_SQL_SCRYPT) == 0) {
  475. crypto_scrypt++;
  476. } else if (strcasecmp(crypto, PASSWD_SQL_CRYPT) == 0) {
  477. crypto_crypt++;
  478. } else if (strcasecmp(crypto, PASSWD_SQL_MD5) == 0) {
  479. crypto_md5++;
  480. } else if (strcasecmp(crypto, PASSWD_SQL_SHA1) == 0) {
  481. crypto_sha1++;
  482. } else { /* default to plaintext */
  483. crypto_plain++;
  484. }
  485. #ifdef crypto_pwhash_STRPREFIX
  486. if (crypto_argon2 != 0) {
  487. if (crypto_pwhash_str_verify(spwd, password, strlen(password)) == 0) {
  488. goto auth_ok;
  489. }
  490. }
  491. #endif
  492. #ifdef crypto_pwhash_scryptsalsa208sha256_STRPREFIX
  493. if (crypto_scrypt != 0) {
  494. if (crypto_pwhash_scryptsalsa208sha256_str_verify
  495. (spwd, password, strlen(password)) == 0) {
  496. goto auth_ok;
  497. }
  498. }
  499. #endif
  500. if (crypto_crypt != 0) {
  501. const char *crypted;
  502. if ((crypted = (const char *) crypt(password, spwd)) != NULL &&
  503. pure_strcmp(crypted, spwd) == 0) {
  504. goto auth_ok;
  505. }
  506. }
  507. if (crypto_md5 != 0) {
  508. const char *crypted;
  509. if ((crypted = (const char *) crypto_hash_md5(password, 1)) != NULL &&
  510. pure_strcmp(crypted, spwd) == 0) {
  511. goto auth_ok;
  512. }
  513. }
  514. if (crypto_sha1 != 0) {
  515. const char *crypted;
  516. if ((crypted = (const char *) crypto_hash_sha1(password, 1)) != NULL &&
  517. pure_strcmp(crypted, spwd) == 0) {
  518. goto auth_ok;
  519. }
  520. }
  521. if (crypto_plain != 0) {
  522. if (*password != 0 && /* refuse null cleartext passwords */
  523. pure_strcmp(password, spwd) == 0) {
  524. goto auth_ok;
  525. }
  526. }
  527. goto bye;
  528. auth_ok:
  529. /*
  530. * do *NOT* accept root uid/gid - if the database is compromized, the FTP
  531. * server could also be rooted.
  532. */
  533. result->uid = (uid_t) strtoul(uid, NULL, 10);
  534. if (result->uid <= (uid_t) 0) {
  535. struct passwd *pw;
  536. if ((pw = getpwnam(uid)) == NULL || pw->pw_uid <= (uid_t) 0) {
  537. goto bye;
  538. }
  539. result->uid = pw->pw_uid;
  540. }
  541. result->gid = (gid_t) strtoul(gid, NULL, 10);
  542. if (result->gid <= (gid_t) 0) {
  543. struct group *gr;
  544. if ((gr = getgrnam(gid)) == NULL || gr->gr_gid <= (gid_t) 0) {
  545. goto bye;
  546. }
  547. result->gid = gr->gr_gid;
  548. }
  549. result->dir = dir;
  550. dir = NULL;
  551. #ifdef QUOTAS
  552. if ((sqta_fs = pw_pgsql_getquery(id_sql_server, sqlreq_getqta_fs,
  553. escaped_account, escaped_ip,
  554. escaped_port, escaped_peer_ip,
  555. escaped_decimal_ip)) != NULL) {
  556. const unsigned long long q = strtoull(sqta_fs, NULL, 10);
  557. if (q > 0ULL) {
  558. result->user_quota_files = q;
  559. result->quota_files_changed = 1;
  560. }
  561. }
  562. if ((sqta_sz = pw_pgsql_getquery(id_sql_server, sqlreq_getqta_sz,
  563. escaped_account, escaped_ip,
  564. escaped_port, escaped_peer_ip,
  565. escaped_decimal_ip)) != NULL) {
  566. const unsigned long long q = strtoull(sqta_sz, NULL, 10);
  567. if (q > 0ULL) {
  568. result->user_quota_size = q * (1024UL * 1024UL);
  569. result->quota_size_changed = 1;
  570. }
  571. }
  572. #endif
  573. #ifdef RATIOS
  574. if ((ratio_ul = pw_pgsql_getquery(id_sql_server, sqlreq_getratio_ul,
  575. escaped_account, escaped_ip,
  576. escaped_port, escaped_peer_ip,
  577. escaped_decimal_ip)) != NULL) {
  578. const unsigned int q = (unsigned int) strtoul(ratio_ul, NULL, 10);
  579. if (q > 0U) {
  580. result->ratio_upload = q;
  581. result->ratio_ul_changed = 1;
  582. }
  583. }
  584. if ((ratio_dl = pw_pgsql_getquery(id_sql_server, sqlreq_getratio_dl,
  585. escaped_account, escaped_ip,
  586. escaped_port, escaped_peer_ip,
  587. escaped_decimal_ip)) != NULL) {
  588. const unsigned int q = (unsigned int) strtoul(ratio_dl, NULL, 10);
  589. if (q > 0U) {
  590. result->ratio_download = q;
  591. result->ratio_dl_changed = 1;
  592. }
  593. }
  594. #endif
  595. #ifdef THROTTLING
  596. if ((bandwidth_ul = pw_pgsql_getquery(id_sql_server, sqlreq_getbandwidth_ul,
  597. escaped_account, escaped_ip,
  598. escaped_port, escaped_peer_ip,
  599. escaped_decimal_ip)) != NULL) {
  600. const unsigned long q = (unsigned long) strtoul(bandwidth_ul, NULL, 10);
  601. if (q > 0UL) {
  602. result->throttling_bandwidth_ul = q * 1024UL;
  603. result->throttling_ul_changed = 1;
  604. }
  605. }
  606. if ((bandwidth_dl = pw_pgsql_getquery(id_sql_server, sqlreq_getbandwidth_dl,
  607. escaped_account, escaped_ip,
  608. escaped_port, escaped_peer_ip,
  609. escaped_decimal_ip)) != NULL) {
  610. const unsigned long q = (unsigned long) strtoul(bandwidth_dl, NULL, 10);
  611. if (q > 0UL) {
  612. result->throttling_bandwidth_dl = q * 1024UL;
  613. result->throttling_dl_changed = 1;
  614. }
  615. }
  616. #endif
  617. result->slow_tilde_expansion = 1;
  618. result->auth_ok = -result->auth_ok;
  619. bye:
  620. if (committed == 0) {
  621. (void) pw_pgsql_simplequery(id_sql_server, PGSQL_TRANSACTION_END);
  622. }
  623. if (id_sql_server != NULL) {
  624. PQfinish(id_sql_server);
  625. }
  626. free((void *) spwd);
  627. if (uid != sql_default_uid) {
  628. free((void *) uid);
  629. }
  630. if (gid != sql_default_gid) {
  631. free((void *) gid);
  632. }
  633. free((void *) dir);
  634. free(scrambled_password);
  635. #ifdef QUOTAS
  636. free((void *) sqta_fs);
  637. free((void *) sqta_sz);
  638. #endif
  639. #ifdef RATIOS
  640. free((void *) ratio_ul);
  641. free((void *) ratio_dl);
  642. #endif
  643. #ifdef THROTTLING
  644. free((void *) bandwidth_ul);
  645. free((void *) bandwidth_dl);
  646. #endif
  647. free((void *) escaped_account);
  648. free((void *) escaped_ip);
  649. free((void *) escaped_port);
  650. free((void *) escaped_peer_ip);
  651. free((void *) escaped_decimal_ip);
  652. }
  653. void pw_pgsql_parse(const char * const file)
  654. {
  655. if (generic_parser(file, pgsql_config_keywords) != 0) {
  656. die(421, LOG_ERR, MSG_CONF_ERR ": " MSG_ILLEGAL_CONFIG_FILE_SQL ": %s" , file);
  657. }
  658. if (server == NULL ) {
  659. die(421, LOG_ERR, MSG_SQL_MISSING_SERVER);
  660. }
  661. if (port_s != NULL) {
  662. port = atoi(port_s);
  663. if (port <= 0 || port > 65535) {
  664. port = PGSQL_DEFAULT_PORT;
  665. }
  666. free(port_s);
  667. port_s = NULL;
  668. }
  669. }
  670. #define ZFREE(X) do { free(X); (X) = NULL; } while (0)
  671. void pw_pgsql_exit(void)
  672. {
  673. ZFREE(server);
  674. ZFREE(port_s);
  675. port = -1;
  676. ZFREE(user);
  677. ZFREE(pw);
  678. ZFREE(db);
  679. ZFREE(crypto);
  680. ZFREE(sqlreq_getpw);
  681. ZFREE(sqlreq_getuid);
  682. ZFREE(sql_default_uid);
  683. ZFREE(sqlreq_getgid);
  684. ZFREE(sql_default_gid);
  685. ZFREE(sqlreq_getdir);
  686. #ifdef QUOTAS
  687. ZFREE(sqlreq_getqta_fs);
  688. ZFREE(sqlreq_getqta_sz);
  689. #endif
  690. #ifdef RATIOS
  691. ZFREE(sqlreq_getratio_ul);
  692. ZFREE(sqlreq_getratio_dl);
  693. #endif
  694. #ifdef THROTTLING
  695. ZFREE(sqlreq_getbandwidth_ul);
  696. ZFREE(sqlreq_getbandwidth_dl);
  697. #endif
  698. }
  699. #else
  700. extern signed char v6ready;
  701. #endif