# Query to retrieve the user information.
#
-# The query must reutrn only one row. The columns to return are home directory,
-# uid, and gid. They do not have to be in any given order, but if they are not
-# named "home", "uid", and "gid", then they must be cast to those names. If
-# more than one row is returned or there's missing fields, login will
-# automatically fail.
+# The query must return only one row. The columns to return are:
+# home - Home directory
+# mail - MAIL environment
+# system_user - System user name (for initgroups())
+# uid - System UID
+# gid - System GID
+# chroot - Chroot to home directory? (Y / N)
+#
+# Either home or mail is required. uid and gid are required. If more than one
+# row is returned or there's missing fields, login will automatically fail.
#
# Examples
# user_query = SELECT home, uid, gid FROM users WHERE userid = '%n' AND domain = '%d'
i_error("PGSQL: Query \"%s\" failed: %s",
query, PQresultErrorMessage(res));
failed = TRUE;
- } else if (PQntuples(res) != 1) {
- i_error("PGSQL: Query \"%s\" returned %d rows",
- query, PQntuples(res));
- failed = TRUE;
} else {
failed = FALSE;
}
request->callback(conn, request, failed ? NULL : res);
PQclear(res);
-
+ i_free(request);
}
static int pgsql_conn_open(struct pgsql_connection *conn)
struct userdb_pgsql_request {
struct pgsql_request request;
userdb_callback_t *userdb_callback;
+
+ char username[1]; /* variable width */
};
static struct userdb_pgsql_connection *userdb_pgsql_conn;
return FALSE;
}
- if (PQfnumber(res, "home") == -1) {
- i_error("PGSQL: User query did not return 'home' field");
- return FALSE;
- }
-
if (PQfnumber(res, "uid") == -1) {
i_error("PGSQL: User query did not return 'uid' field");
return FALSE;
return TRUE;
}
+static const char *pg_get_str(PGresult *res, const char *field)
+{
+ int fieldnum;
+
+ fieldnum = PQfnumber(res, field);
+ return fieldnum == -1 ? NULL : PQgetvalue(res, 0, fieldnum);
+}
+
static void pgsql_handle_request(struct pgsql_connection *conn __attr_unused__,
struct pgsql_request *request, PGresult *res)
{
struct userdb_pgsql_request *urequest =
(struct userdb_pgsql_request *) request;
struct user_data user;
+ const char *str;
if (res != NULL && is_result_valid(res)) {
memset(&user, 0, sizeof(user));
- user.home = PQgetvalue(res, 0, PQfnumber(res, "home"));
+ user.virtual_user = urequest->username;
+ user.system_user = pg_get_str(res, "system_user");
+ user.home = pg_get_str(res, "home");
+ user.mail = pg_get_str(res, "mail");
user.uid = atoi(PQgetvalue(res, 0, PQfnumber(res, "uid")));
user.gid = atoi(PQgetvalue(res, 0, PQfnumber(res, "gid")));
+ str = pg_get_str(res, "chroot");
+ user.chroot = str != NULL && (*str == 'Y' || *str == 'y');
urequest->userdb_callback(&user, request->context);
} else {
urequest->userdb_callback(NULL, request->context);
var_expand(str, conn->set.user_query, str_escape(user), NULL);
query = str_c(str);
- request = i_new(struct userdb_pgsql_request, 1);
+ request = i_malloc(sizeof(struct userdb_pgsql_request) + strlen(user));
request->request.callback = pgsql_handle_request;
request->request.context = context;
request->userdb_callback = callback;
+ strcpy(request->username, user);
db_pgsql_query(conn, query, &request->request);
}