6 ** Maya Nigrosh -- original store() and txn support
7 ** Simon Loader -- original mysql plugin
8 ** Patrick Welche -- original pgsql plugin
10 ** $Id: sql.c,v 1.29 2006/04/07 13:42:16 jeaton Exp $
27 #include "plugin_common.h"
29 #define sql_max(a, b) ((a) > (b) ? (a) : (b))
30 #define sql_len(input) ((input) ? strlen(input) : 0)
31 #define sql_exists(input) ((input) && (*input))
33 typedef struct sql_engine {
35 void *(*sql_open)(char *host, char *port, int usessl,
36 const char *user, const char *password,
37 const char *database, const sasl_utils_t *utils);
38 int (*sql_escape_str)(char *to, const char *from);
39 int (*sql_begin_txn)(void *conn, const sasl_utils_t *utils);
40 int (*sql_commit_txn)(void *conn, const sasl_utils_t *utils);
41 int (*sql_rollback_txn)(void *conn, const sasl_utils_t *utils);
42 int (*sql_exec)(void *conn, const char *cmd, char *value, size_t size,
43 size_t *value_len, const sasl_utils_t *utils);
44 void (*sql_close)(void *conn);
47 typedef struct sql_settings {
48 const sql_engine_t *sql_engine;
50 const char *sql_passwd;
51 const char *sql_hostnames;
52 const char *sql_database;
53 const char *sql_select;
54 const char *sql_insert;
55 const char *sql_update;
59 static const char * SQL_BLANK_STRING = "";
60 static const char * SQL_WILDCARD = "*";
61 static const char * SQL_NULL_VALUE = "NULL";
67 static void *_mysql_open(char *host, char *port, int usessl,
68 const char *user, const char *password,
69 const char *database, const sasl_utils_t *utils)
73 if (!(mysql = mysql_init(NULL))) {
74 utils->log(NULL, SASL_LOG_ERR,
75 "sql plugin: could not execute mysql_init()");
79 return mysql_real_connect(mysql, host, user, password, database,
80 port ? strtoul(port, NULL, 10) : 0, NULL,
81 usessl ? CLIENT_SSL : 0);
84 static int _mysql_escape_str(char *to, const char *from)
86 return mysql_escape_string(to, from, strlen(from));
89 static int _mysql_exec(void *conn, const char *cmd, char *value, size_t size,
90 size_t *value_len, const sasl_utils_t *utils)
97 /* mysql_real_query() doesn't want a terminating ';' */
98 if (cmd[len-1] == ';') len--;
101 * Run the query. It is important to note that mysql_real_query
102 * will return success even if the sql statement
103 * had an error in it. However, mysql_errno() will alsways
104 * tell us if there was an error. Therefore we can ignore
105 * the result from mysql_real_query and simply check mysql_errno()
106 * to decide if there was really an error.
108 (void)mysql_real_query(conn, cmd, len);
110 if(mysql_errno(conn)) {
111 utils->log(NULL, SASL_LOG_ERR, "sql query failed: %s",
116 /* see if we should expect some results */
117 if (!mysql_field_count(conn)) {
118 /* no results (BEGIN, COMMIT, DELETE, INSERT, UPDATE) */
122 /* get the results */
123 result = mysql_store_result(conn);
125 /* umm nothing found */
126 utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
130 /* quick row check */
131 row_count = mysql_num_rows(result);
133 /* umm nothing found */
134 mysql_free_result(result);
135 utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
139 utils->log(NULL, SASL_LOG_WARN,
140 "sql plugin: found duplicate row for query %s", cmd);
143 /* now get the result set value and value_len */
144 /* we only fetch one because we don't care about the rest */
145 row = mysql_fetch_row(result);
146 if (!row || !row[0]) {
147 /* umm nothing found */
148 utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
149 mysql_free_result(result);
153 strncpy(value, row[0], size-2);
154 value[size-1] = '\0';
155 if (value_len) *value_len = strlen(value);
159 mysql_free_result(result);
164 static int _mysql_begin_txn(void *conn, const sasl_utils_t *utils)
166 return _mysql_exec(conn,
167 #if MYSQL_VERSION_ID >= 40011
172 NULL, 0, NULL, utils);
175 static int _mysql_commit_txn(void *conn, const sasl_utils_t *utils)
177 return _mysql_exec(conn, "COMMIT", NULL, 0, NULL, utils);
180 static int _mysql_rollback_txn(void *conn, const sasl_utils_t *utils)
182 return _mysql_exec(conn, "ROLLBACK", NULL, 0, NULL, utils);
185 static void _mysql_close(void *conn)
189 #endif /* HAVE_MYSQL */
192 #include <libpq-fe.h>
194 static void *_pgsql_open(char *host, char *port, int usessl,
195 const char *user, const char *password,
196 const char *database, const sasl_utils_t *utils)
199 char *conninfo, *sep;
201 /* create the connection info string */
202 /* The 64 represents the number of characters taken by
203 * the keyword tokens, plus a small pad
205 conninfo = utils->malloc(64 + sql_len(host) + sql_len(port)
206 + sql_len(user) + sql_len(password)
207 + sql_len(database));
213 /* add each term that exists */
216 if (sql_exists(host)) {
217 strcat(conninfo, sep);
218 strcat(conninfo, "host='");
219 strcat(conninfo, host);
220 strcat(conninfo, "'");
223 if (sql_exists(port)) {
224 strcat(conninfo, sep);
225 strcat(conninfo, "port='");
226 strcat(conninfo, port);
227 strcat(conninfo, "'");
230 if (sql_exists(user)) {
231 strcat(conninfo, sep);
232 strcat(conninfo, "user='");
233 strcat(conninfo, user);
234 strcat(conninfo, "'");
237 if (sql_exists(password)) {
238 strcat(conninfo, sep);
239 strcat(conninfo, "password='");
240 strcat(conninfo, password);
241 strcat(conninfo, "'");
244 if (sql_exists(database)) {
245 strcat(conninfo, sep);
246 strcat(conninfo, "dbname='");
247 strcat(conninfo, database);
248 strcat(conninfo, "'");
252 strcat(conninfo, sep);
253 strcat(conninfo, "requiressl='1'");
256 conn = PQconnectdb(conninfo);
259 if ((PQstatus(conn) != CONNECTION_OK)) {
260 utils->log(NULL, SASL_LOG_ERR, "sql plugin: %s", PQerrorMessage(conn));
267 static int _pgsql_escape_str(char *to, const char *from)
269 return PQescapeString(to, from, strlen(from));
272 static int _pgsql_exec(void *conn, const char *cmd, char *value, size_t size,
273 size_t *value_len, const sasl_utils_t *utils)
277 ExecStatusType status;
280 result = PQexec(conn, cmd);
282 /* check the status */
283 status = PQresultStatus(result);
284 if (status == PGRES_COMMAND_OK) {
285 /* no results (BEGIN, COMMIT, DELETE, INSERT, UPDATE) */
289 else if (status != PGRES_TUPLES_OK) {
291 utils->log(NULL, SASL_LOG_DEBUG, "sql plugin: %s ",
292 PQresStatus(status));
297 /* quick row check */
298 row_count = PQntuples(result);
300 /* umm nothing found */
301 utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
306 utils->log(NULL, SASL_LOG_WARN,
307 "sql plugin: found duplicate row for query %s", cmd);
310 /* now get the result set value and value_len */
311 /* we only fetch one because we don't care about the rest */
313 strncpy(value, PQgetvalue(result,0,0), size-2);
314 value[size-1] = '\0';
315 if (value_len) *value_len = strlen(value);
323 static int _pgsql_begin_txn(void *conn, const sasl_utils_t *utils)
325 return _pgsql_exec(conn, "BEGIN;", NULL, 0, NULL, utils);
328 static int _pgsql_commit_txn(void *conn, const sasl_utils_t *utils)
330 return _pgsql_exec(conn, "COMMIT;", NULL, 0, NULL, utils);
333 static int _pgsql_rollback_txn(void *conn, const sasl_utils_t *utils)
335 return _pgsql_exec(conn, "ROLLBACK;", NULL, 0, NULL, utils);
338 static void _pgsql_close(void *conn)
342 #endif /* HAVE_PGSQL */
347 static void *_sqlite_open(char *host __attribute__((unused)),
348 char *port __attribute__((unused)),
349 int usessl __attribute__((unused)),
350 const char *user __attribute__((unused)),
351 const char *password __attribute__((unused)),
352 const char *database, const sasl_utils_t *utils)
356 char *zErrMsg = NULL;
358 db = sqlite_open(database, 0, &zErrMsg);
360 utils->log(NULL, SASL_LOG_ERR, "sql plugin: %s", zErrMsg);
361 sqlite_freemem (zErrMsg);
365 rc = sqlite_exec(db, "PRAGMA empty_result_callbacks = ON", NULL, NULL, &zErrMsg);
366 if (rc != SQLITE_OK) {
367 utils->log(NULL, SASL_LOG_ERR, "sql plugin: %s", zErrMsg);
368 sqlite_freemem (zErrMsg);
376 static int _sqlite_escape_str(char *to, const char *from)
380 while ( (s = *from++) != '\0' ) {
381 if (s == '\'' || s == '\\') {
391 static int sqlite_my_callback(void *pArg, int argc __attribute__((unused)),
393 char **columnNames __attribute__((unused)))
395 char **result = (char**)pArg;
398 *result = NULL; /* no record */
399 } else if (argv[0] == NULL) {
400 *result = strdup(SQL_NULL_VALUE); /* NULL IS SQL_NULL_VALUE */
402 *result = strdup(argv[0]);
408 static int _sqlite_exec(void *db, const char *cmd, char *value, size_t size,
409 size_t *value_len, const sasl_utils_t *utils)
413 char *zErrMsg = NULL;
415 rc = sqlite_exec((sqlite*)db, cmd, sqlite_my_callback, (void*)&result, &zErrMsg);
416 if (rc != SQLITE_OK && rc != SQLITE_ABORT) {
417 utils->log(NULL, SASL_LOG_DEBUG, "sql plugin: %s ", zErrMsg);
418 sqlite_freemem (zErrMsg);
422 if (rc == SQLITE_OK) {
423 /* no results (BEGIN, COMMIT, DELETE, INSERT, UPDATE) */
427 if (result == NULL) {
428 /* umm nothing found */
429 utils->log(NULL, SASL_LOG_NOTE, "sql plugin: no result found");
433 /* XXX: Duplication cannot be found by this method. */
435 /* now get the result set value and value_len */
436 /* we only fetch one because we don't care about the rest */
438 strncpy(value, result, size - 2);
439 value[size - 1] = '\0';
441 *value_len = strlen(value);
450 static int _sqlite_begin_txn(void *db, const sasl_utils_t *utils)
452 return _sqlite_exec(db, "BEGIN TRANSACTION", NULL, 0, NULL, utils);
455 static int _sqlite_commit_txn(void *db, const sasl_utils_t *utils)
457 return _sqlite_exec(db, "COMMIT TRANSACTION", NULL, 0, NULL, utils);
460 static int _sqlite_rollback_txn(void *db, const sasl_utils_t *utils)
462 return _sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, 0, NULL, utils);
465 static void _sqlite_close(void *db)
467 sqlite_close((sqlite*)db);
469 #endif /* HAVE_SQLITE */
471 static const sql_engine_t sql_engines[] = {
473 { "mysql", &_mysql_open, &_mysql_escape_str,
474 &_mysql_begin_txn, &_mysql_commit_txn, &_mysql_rollback_txn,
475 &_mysql_exec, &_mysql_close },
476 #endif /* HAVE_MYSQL */
478 { "pgsql", &_pgsql_open, &_pgsql_escape_str,
479 &_pgsql_begin_txn, &_pgsql_commit_txn, &_pgsql_rollback_txn,
480 &_pgsql_exec, &_pgsql_close },
483 { "sqlite", &_sqlite_open, &_sqlite_escape_str,
484 &_sqlite_begin_txn, &_sqlite_commit_txn, &_sqlite_rollback_txn,
485 &_sqlite_exec, &_sqlite_close },
487 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
491 ** Sql_create_statement
492 ** uses statement line and allocate memory to replace
493 ** Parts with the strings provided.
494 ** %<char> = no change
499 ** %v = value of prop
500 ** e.g select %p from auth where user = %p and domain = %r;
501 ** Note: calling function must free memory.
505 static char *sql_create_statement(const char *statement, const char *prop,
506 const char *user, const char *realm,
508 const sasl_utils_t *utils)
510 const char *ptr, *line_ptr;
513 int ulen, plen, rlen, vlen;
518 /* calculate memory needed for creating the complete query string. */
520 rlen = strlen(realm);
522 vlen = sql_len(value);
524 /* what if we have multiple %foo occurrences in the input query? */
525 for (i = 0; i < strlen(statement); i++) {
526 if (statement[i] == '%') {
531 /* find the biggest of ulen, rlen, plen, vlen */
532 biggest = sql_max(sql_max(ulen, rlen), sql_max(plen, vlen));
534 /* plus one for the semicolon...and don't forget the trailing 0x0 */
535 filtersize = strlen(statement) + 1 + (numpercents*biggest)+1;
537 /* ok, now try to allocate a chunk of that size */
538 buf = (char *) utils->malloc(filtersize);
546 line_ptr = statement;
548 /* replace the strings */
549 while ( (ptr = strchr(line_ptr, '%')) ) {
550 /* copy up to but not including the next % */
551 memcpy(buf_ptr, line_ptr, ptr - line_ptr);
552 buf_ptr += ptr - line_ptr;
560 memcpy(buf_ptr, user, ulen);
564 memcpy(buf_ptr, realm, rlen);
568 memcpy(buf_ptr, prop, plen);
573 memcpy(buf_ptr, value, vlen);
577 utils->log(NULL, SASL_LOG_ERR,
578 "'%%v' shouldn't be in a SELECT or DELETE");
591 memcpy(buf_ptr, line_ptr, strlen(line_ptr)+1);
592 /* Make sure the current portion of the statement ends with a semicolon */
593 if (buf_ptr[strlen(buf_ptr-1)] != ';') {
594 strcat(buf_ptr, ";");
602 * Get the auxprop settings and put them in the global context array
604 static void sql_get_settings(const sasl_utils_t *utils, void *glob_context)
606 sql_settings_t *settings;
608 const char *usessl, *engine_name;
609 const sql_engine_t *e;
611 settings = (sql_settings_t *) glob_context;
613 r = utils->getopt(utils->getopt_context,"SQL", "sql_engine",
615 if (r || !engine_name) {
616 engine_name = "mysql";
619 /* find the correct engine */
622 if (!strcasecmp(engine_name, e->name)) break;
627 utils->log(NULL, SASL_LOG_ERR, "SQL engine '%s' not supported",
631 settings->sql_engine = e;
633 r = utils->getopt(utils->getopt_context,"SQL","sql_user",
634 &settings->sql_user, NULL);
635 if ( r || !settings->sql_user ) {
636 settings->sql_user = SQL_BLANK_STRING;
639 r = utils->getopt(utils->getopt_context,"SQL", "sql_passwd",
640 &settings->sql_passwd, NULL);
641 if (r || !settings->sql_passwd ) {
642 settings->sql_passwd = SQL_BLANK_STRING;
645 r = utils->getopt(utils->getopt_context,"SQL", "sql_hostnames",
646 &settings->sql_hostnames, NULL);
647 if (r || !settings->sql_hostnames ) {
648 settings->sql_hostnames = SQL_BLANK_STRING;
651 r = utils->getopt(utils->getopt_context,"SQL", "sql_database",
652 &settings->sql_database, NULL);
653 if (r || !settings->sql_database ) {
654 settings->sql_database = SQL_BLANK_STRING;
657 r = utils->getopt(utils->getopt_context,"SQL", "sql_select",
658 &settings->sql_select, NULL);
659 if (r || !settings->sql_select ) {
660 /* backwards compatibility */
661 r = utils->getopt(utils->getopt_context,"SQL", "sql_statement",
662 &settings->sql_select, NULL);
663 if (r || !settings->sql_select) {
664 settings->sql_select = SQL_BLANK_STRING;
668 r = utils->getopt(utils->getopt_context, "SQL", "sql_insert",
669 &settings->sql_insert, NULL);
670 if (r || !settings->sql_insert) {
671 settings->sql_insert = SQL_BLANK_STRING;
674 r = utils->getopt(utils->getopt_context, "SQL", "sql_update",
675 &settings->sql_update, NULL);
676 if (r || !settings->sql_update) {
677 settings->sql_update = SQL_BLANK_STRING;
680 r = utils->getopt(utils->getopt_context, "SQL", "sql_usessl",
682 if (r || !usessl) usessl = "no";
684 if (*usessl == '1' || *usessl == 'y' || *usessl == 't' ||
685 (*usessl == 'o' && usessl[1] == 'n')) {
686 settings->sql_usessl = 1;
688 settings->sql_usessl = 0;
692 static void *sql_connect(sql_settings_t *settings, const sasl_utils_t *utils)
695 char *db_host_ptr = NULL;
696 char *db_host = NULL;
697 char *cur_host, *cur_port;
699 /* loop around hostnames till we get a connection
700 * it should probably save the connection but for
701 * now we will just disconnect everytime
703 utils->log(NULL, SASL_LOG_DEBUG,
704 "sql plugin try and connect to a host\n");
706 /* create a working version of the hostnames */
707 _plug_strdup(utils, settings->sql_hostnames, &db_host_ptr, NULL);
708 db_host = db_host_ptr;
710 while (cur_host != NULL) {
711 db_host = strchr(db_host,',');
712 if (db_host != NULL) {
715 /* loop till we find some text */
716 while (!isalnum(db_host[0])) db_host++;
719 utils->log(NULL, SASL_LOG_DEBUG,
720 "sql plugin trying to open db '%s' on host '%s'%s\n",
721 settings->sql_database, cur_host,
722 settings->sql_usessl ? " using SSL" : "");
724 /* set the optional port */
725 if ((cur_port = strchr(cur_host, ':'))) *cur_port++ = '\0';
727 conn = settings->sql_engine->sql_open(cur_host, cur_port,
728 settings->sql_usessl,
730 settings->sql_passwd,
731 settings->sql_database,
735 utils->log(NULL, SASL_LOG_ERR,
736 "sql plugin could not connect to host %s", cur_host);
741 if (db_host_ptr) utils->free(db_host_ptr);
746 static void sql_auxprop_lookup(void *glob_context,
747 sasl_server_params_t *sparams,
753 /* realm could be used for something clever */
755 const char *user_realm = NULL;
756 const struct propval *to_fetch, *cur;
762 char *escap_userid = NULL;
763 char *escap_realm = NULL;
764 sql_settings_t *settings;
768 if (!glob_context || !sparams || !user) return;
770 /* setup the settings */
771 settings = (sql_settings_t *) glob_context;
773 sparams->utils->log(NULL, SASL_LOG_DEBUG,
774 "sql plugin Parse the username %s\n", user);
776 user_buf = sparams->utils->malloc(ulen + 1);
777 if (!user_buf) goto done;
779 memcpy(user_buf, user, ulen);
780 user_buf[ulen] = '\0';
782 if(sparams->user_realm) {
783 user_realm = sparams->user_realm;
785 user_realm = sparams->serverFQDN;
788 if (_plug_parseuser(sparams->utils, &userid, &realm, user_realm,
789 sparams->serverFQDN, user_buf) != SASL_OK )
792 /* just need to escape userid and realm now */
793 /* allocate some memory */
794 escap_userid = (char *)sparams->utils->malloc(strlen(userid)*2+1);
795 escap_realm = (char *)sparams->utils->malloc(strlen(realm)*2+1);
797 if (!escap_userid || !escap_realm) {
798 MEMERROR(sparams->utils);
802 /*************************************/
804 /* find out what we need to get */
805 /* this corrupts const char *user */
806 to_fetch = sparams->utils->prop_get(sparams->propctx);
807 if (!to_fetch) goto done;
809 conn = sql_connect(settings, sparams->utils);
811 sparams->utils->log(NULL, SASL_LOG_ERR,
812 "sql plugin couldn't connect to any host\n");
818 settings->sql_engine->sql_escape_str(escap_userid, userid);
819 settings->sql_engine->sql_escape_str(escap_realm, realm);
821 for (cur = to_fetch; cur->name; cur++) {
822 char *realname = (char *) cur->name;
824 /* Only look up properties that apply to this lookup! */
825 if (cur->name[0] == '*'
826 && (flags & SASL_AUXPROP_AUTHZID))
828 if (!(flags & SASL_AUXPROP_AUTHZID)) {
829 if(cur->name[0] != '*')
832 realname = (char*)cur->name + 1;
835 /* If it's there already, we want to see if it needs to be
837 if (cur->values && !(flags & SASL_AUXPROP_OVERRIDE))
839 else if (cur->values)
840 sparams->utils->prop_erase(sparams->propctx, cur->name);
844 sparams->utils->log(NULL, SASL_LOG_DEBUG, "begin transaction");
845 if (settings->sql_engine->sql_begin_txn(conn, sparams->utils)) {
846 sparams->utils->log(NULL, SASL_LOG_ERR,
847 "Unable to begin transaction\n");
851 sparams->utils->log(NULL, SASL_LOG_DEBUG,
852 "sql plugin create statement from %s %s %s\n",
853 realname, escap_userid, escap_realm);
855 /* create a statement that we will use */
856 query = sql_create_statement(settings->sql_select,
857 realname,escap_userid,
861 sparams->utils->log(NULL, SASL_LOG_DEBUG,
862 "sql plugin doing query %s\n", query);
865 if (!settings->sql_engine->sql_exec(conn, query, value, sizeof(value),
866 &value_len, sparams->utils)) {
867 sparams->utils->prop_set(sparams->propctx, cur->name,
871 sparams->utils->free(query);
875 sparams->utils->log(NULL, SASL_LOG_DEBUG, "commit transaction");
876 if (settings->sql_engine->sql_commit_txn(conn, sparams->utils)) {
877 sparams->utils->log(NULL, SASL_LOG_ERR,
878 "Unable to commit transaction\n");
883 if (escap_userid) sparams->utils->free(escap_userid);
884 if (escap_realm) sparams->utils->free(escap_realm);
885 if (conn) settings->sql_engine->sql_close(conn);
886 if (userid) sparams->utils->free(userid);
887 if (realm) sparams->utils->free(realm);
888 if (user_buf) sparams->utils->free(user_buf);
891 static int sql_auxprop_store(void *glob_context,
892 sasl_server_params_t *sparams,
899 const char *user_realm = NULL;
901 const struct propval *to_store, *cur;
904 char *statement = NULL;
905 char *escap_userid = NULL;
906 char *escap_realm = NULL;
909 sql_settings_t *settings;
912 settings = (sql_settings_t *) glob_context;
914 /* just checking if we are enabled */
916 sql_exists(settings->sql_insert) &&
917 sql_exists(settings->sql_update)) return SASL_OK;
919 /* make sure our input is okay */
920 if (!glob_context || !sparams || !user) return SASL_BADPARAM;
922 sparams->utils->log(NULL, SASL_LOG_DEBUG,
923 "sql plugin Parse the username %s\n", user);
925 user_buf = sparams->utils->malloc(ulen + 1);
931 memcpy(user_buf, user, ulen);
932 user_buf[ulen] = '\0';
934 if (sparams->user_realm) {
935 user_realm = sparams->user_realm;
938 user_realm = sparams->serverFQDN;
941 ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
942 sparams->serverFQDN, user_buf);
943 if (ret != SASL_OK) goto done;
945 /* just need to escape userid and realm now */
946 /* allocate some memory */
948 escap_userid = (char *) sparams->utils->malloc(strlen(userid)*2+1);
949 escap_realm = (char *) sparams->utils->malloc(strlen(realm)*2+1);
951 if (!escap_userid || !escap_realm) {
952 MEMERROR(sparams->utils);
956 to_store = sparams->utils->prop_get(ctx);
963 conn = sql_connect(settings, sparams->utils);
965 sparams->utils->log(NULL, SASL_LOG_ERR,
966 "sql plugin couldn't connect to any host\n");
970 settings->sql_engine->sql_escape_str(escap_userid, userid);
971 settings->sql_engine->sql_escape_str(escap_realm, realm);
973 if (settings->sql_engine->sql_begin_txn(conn, sparams->utils)) {
974 sparams->utils->log(NULL, SASL_LOG_ERR,
975 "Unable to begin transaction\n");
977 for (cur = to_store; ret == SASL_OK && cur->name; cur++) {
978 /* determine which command we need */
979 /* see if we already have a row for this user */
980 statement = sql_create_statement(settings->sql_select,
981 SQL_WILDCARD, escap_userid,
984 if (!settings->sql_engine->sql_exec(conn, statement, NULL, 0, NULL,
986 /* already have a row => UPDATE */
987 cmd = settings->sql_update;
989 /* new row => INSERT */
990 cmd = settings->sql_insert;
992 sparams->utils->free(statement);
994 /* create a statement that we will use */
995 statement = sql_create_statement(cmd, cur->name, escap_userid,
997 cur->values && cur->values[0] ?
998 cur->values[0] : SQL_NULL_VALUE,
1002 char *log_statement =
1003 sql_create_statement(cmd, cur->name,
1006 cur->values && cur->values[0] ?
1007 "<omitted>" : SQL_NULL_VALUE,
1009 sparams->utils->log(NULL, SASL_LOG_DEBUG,
1010 "sql plugin doing statement %s\n",
1012 sparams->utils->free(log_statement);
1015 /* run the statement */
1016 if (settings->sql_engine->sql_exec(conn, statement, NULL, 0, NULL,
1021 sparams->utils->free(statement);
1023 if (ret != SASL_OK) {
1024 sparams->utils->log(NULL, SASL_LOG_ERR,
1025 "Failed to store auxprop; aborting transaction\n");
1026 if (settings->sql_engine->sql_rollback_txn(conn, sparams->utils)) {
1027 sparams->utils->log(NULL, SASL_LOG_ERR,
1028 "Unable to rollback transaction\n");
1031 else if (settings->sql_engine->sql_commit_txn(conn, sparams->utils)) {
1032 sparams->utils->log(NULL, SASL_LOG_ERR,
1033 "Unable to commit transaction\n");
1037 if (escap_userid) sparams->utils->free(escap_userid);
1038 if (escap_realm) sparams->utils->free(escap_realm);
1039 if (conn) settings->sql_engine->sql_close(conn);
1040 if (userid) sparams->utils->free(userid);
1041 if (realm) sparams->utils->free(realm);
1042 if (user_buf) sparams->utils->free(user_buf);
1046 /* do a little dance */
1050 static void sql_auxprop_free(void *glob_context, const sasl_utils_t *utils)
1052 sql_settings_t *settings;
1054 settings = (sql_settings_t *)glob_context;
1056 if (!settings) return;
1058 utils->log(NULL, SASL_LOG_DEBUG, "sql freeing memory\n");
1060 utils->free(settings);
1063 static sasl_auxprop_plug_t sql_auxprop_plugin = {
1066 NULL, /* glob_context */
1067 sql_auxprop_free, /* auxprop_free */
1068 sql_auxprop_lookup, /* auxprop_lookup */
1070 sql_auxprop_store /* auxprop_store */
1073 int sql_auxprop_plug_init(const sasl_utils_t *utils,
1076 sasl_auxprop_plug_t **plug,
1077 const char *plugname __attribute__((unused)))
1079 sql_settings_t *settings;
1081 if (!out_version || !plug) return SASL_BADPARAM;
1083 if (max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
1084 *out_version = SASL_AUXPROP_PLUG_VERSION;
1086 *plug = &sql_auxprop_plugin;
1088 settings = (sql_settings_t *) utils->malloc(sizeof(sql_settings_t));
1095 memset(settings, 0, sizeof(sql_settings_t));
1096 sql_get_settings(utils, settings);
1098 if (!settings->sql_engine->name) return SASL_NOMECH;
1100 if (!sql_exists(settings->sql_select)) {
1101 utils->log(NULL, SASL_LOG_ERR, "sql_select option missing");
1102 utils->free(settings);
1106 utils->log(NULL, SASL_LOG_DEBUG,
1107 "sql auxprop plugin using %s engine\n",
1108 settings->sql_engine->name);
1110 sql_auxprop_plugin.glob_context = settings;