1 /*
    2  * WARNING: automatically generated by ort-c-source 0.8.5.
    3  * DO NOT EDIT!
    4  */
    5 #include <sys/queue.h>
    6 
    7 #include <assert.h>
    8 #include <stdarg.h>
    9 #include <stdio.h>
   10 #include <stdint.h> /* int64_t */
   11 #include <stdlib.h>
   12 #include <string.h>
   13 #include <time.h> /* _XOPEN_SOURCE and gmtime_r()*/
   14 #include <unistd.h>
   15 
   16 #include <sqlbox.h>
   17 #include <kcgi.h>
   18 #include <kcgijson.h>
   19 
   20 #include "kwebapp.db.h"
   21 
   22 /*
   23  * All SQL statements we'll later define in "stmts".
   24  */
   25 enum	stmt {
   26 	STMT_USER_BY_UNIQUE_email,
   27 	STMT_USER_BY_UNIQUE_id,
   28 	STMT_USER_BY_SEARCH_0,
   29 	STMT_SESS_BY_UNIQUE_id,
   30 	STMT_SESS_BY_SEARCH_0,
   31 	STMT_SESS_DELETE_0,
   32 	STMT__MAX
   33 };
   34 
   35 /*
   36  * Definition of our opaque "ort", which contains role information.
   37  */
   38 struct	ort {
   39 	/* Hidden database connection */
   40 	struct sqlbox *db;
   41 };
   42 
   43 /*
   44  * Define our table columns.
   45  * Since we're using roles, this is all internal to the source and not 
   46  * exported.
   47  */
   48 #define DB_SCHEMA_USER(_x) \
   49 	#_x ".email" "," \
   50 	#_x ".hash" "," \
   51 	#_x ".id"
   52 #define DB_SCHEMA_SESS(_x) \
   53 	#_x ".userid" "," \
   54 	#_x ".token" "," \
   55 	#_x ".id"
   56 
   57 /*
   58  * Our full set of SQL statements.
   59  * We define these beforehand because that's how sqlbox(3) handles 
   60  * statement generation.
   61  * Notice the "AS" part: this allows for multiple inner joins without 
   62  * ambiguity.
   63  */
   64 static	const char *const stmts[STMT__MAX] = {
   65 	/* STMT_USER_BY_UNIQUE_email */
   66 	"SELECT " DB_SCHEMA_USER(user) " FROM user WHERE user.email = ?",
   67 	/* STMT_USER_BY_UNIQUE_id */
   68 	"SELECT " DB_SCHEMA_USER(user) " FROM user WHERE user.id = ?",
   69 	/* STMT_USER_BY_SEARCH_0 */
   70 	"SELECT " DB_SCHEMA_USER(user) " FROM user "
   71 		"WHERE user.email = ?",
   72 	/* STMT_SESS_BY_UNIQUE_id */
   73 	"SELECT " DB_SCHEMA_SESS(sess) "," DB_SCHEMA_USER(_a) " FROM sess "
   74 		"INNER JOIN user AS _a ON _a.id=sess.userid "
   75 		"WHERE sess.id = ?",
   76 	/* STMT_SESS_BY_SEARCH_0 */
   77 	"SELECT " DB_SCHEMA_SESS(sess) "," DB_SCHEMA_USER(_a) " FROM sess "
   78 		"INNER JOIN user AS _a ON _a.id=sess.userid "
   79 		"WHERE sess.token = ? AND sess.id = ?",
   80 	/* STMT_SESS_DELETE_0 */
   81 	"DELETE FROM sess WHERE id = ?",
   82 };
   83 
   84 const struct kvalid valid_keys[VALID__MAX] = {
   85 	{ valid_user_email, "user-email" },
   86 	{ valid_user_hash, "user-hash" },
   87 	{ valid_user_id, "user-id" },
   88 	{ valid_sess_userid, "sess-userid" },
   89 	{ valid_sess_token, "sess-token" },
   90 	{ valid_sess_id, "sess-id" },
   91 };
   92 
   93 /*
   94  * Finally, all of the functions we'll use.
   95  */
   96 
   97 void
   98 db_trans_open(struct ort *ctx, size_t id, int mode)
   99 {
  100 	struct sqlbox *db = ctx->db;
  101 	int c;
  102 
  103 	if (mode < 0)
  104 		c = sqlbox_trans_exclusive(db, 0, id);
  105 	else if (mode > 0)
  106 		c = sqlbox_trans_immediate(db, 0, id);
  107 	else
  108 		c = sqlbox_trans_deferred(db, 0, id);
  109 	if (!c)
  110 		exit(EXIT_FAILURE);
  111 }
  112 
  113 void
  114 db_trans_rollback(struct ort *ctx, size_t id)
  115 {
  116 	struct sqlbox *db = ctx->db;
  117 
  118 	if (!sqlbox_trans_rollback(db, 0, id))
  119 		exit(EXIT_FAILURE);
  120 }
  121 
  122 void
  123 db_trans_commit(struct ort *ctx, size_t id)
  124 {
  125 	struct sqlbox *db = ctx->db;
  126 
  127 	if (!sqlbox_trans_commit(db, 0, id))
  128 		exit(EXIT_FAILURE);
  129 }
  130 
  131 void
  132 db_logging_data(struct ort *ort, const void *arg, size_t sz)
  133 {
  134 
  135 	if (!sqlbox_msg_set_dat(ort->db, arg, sz))
  136 		exit(EXIT_FAILURE);
  137 }
  138 
  139 struct ort *
  140 db_open(const char *file)
  141 {
  142 
  143 	return db_open_logging(file, NULL, NULL, NULL);
  144 }
  145 
  146 struct ort *
  147 db_open_logging(const char *file,
  148 	void (*log)(const char *, void *),
  149 	void (*log_short)(const char *, ...), void *log_arg)
  150 {
  151 	size_t i;
  152 	struct ort *ctx = NULL;
  153 	struct sqlbox_cfg cfg;
  154 	struct sqlbox *db = NULL;
  155 	struct sqlbox_pstmt pstmts[STMT__MAX];
  156 	struct sqlbox_src srcs[1] = {
  157 		{ .fname = (char *)file,
  158 		  .mode = SQLBOX_SRC_RW }
  159 	};
  160 
  161 	memset(&cfg, 0, sizeof(struct sqlbox_cfg));
  162 	cfg.msg.func = log;
  163 	cfg.msg.func_short = log_short;
  164 	cfg.msg.dat = log_arg;
  165 	cfg.srcs.srcs = srcs;
  166 	cfg.srcs.srcsz = 1;
  167 	cfg.stmts.stmts = pstmts;
  168 	cfg.stmts.stmtsz = STMT__MAX;
  169 
  170 	for (i = 0; i < STMT__MAX; i++)
  171 		pstmts[i].stmt = (char *)stmts[i];
  172 
  173 	ctx = malloc(sizeof(struct ort));
  174 	if (ctx == NULL)
  175 		goto err;
  176 
  177 	if ((db = sqlbox_alloc(&cfg)) == NULL)
  178 		goto err;
  179 	ctx->db = db;
  180 
  181 	/*
  182 	 * Now actually open the database.
  183 	 * If this succeeds, then we're good to go.
  184 	 */
  185 
  186 	if (sqlbox_open_async(db, 0))
  187 		return ctx;
  188 err:
  189 	sqlbox_free(db);
  190 	free(ctx);
  191 	return NULL;
  192 }
  193 
  194 void
  195 db_close(struct ort *p)
  196 {
  197 	if (p == NULL)
  198 		return;
  199 	sqlbox_free(p->db);
  200 	free(p);
  201 }
  202 
  203 /*
  204  * Fill in a user from an open statement "stmt".
  205  * This starts grabbing results from "pos", which may be NULL to start 
  206  * from zero.
  207  * This follows DB_SCHEMA_USER's order for columns.
  208  */
  209 static void
  210 db_user_fill(struct ort *ctx, struct user *p, const struct sqlbox_parmset *set, size_t *pos)
  211 {
  212 	size_t i = 0;
  213 
  214 	if (pos == NULL)
  215 		pos = &i;
  216 	memset(p, 0, sizeof(*p));
  217 	if (sqlbox_parm_string_alloc
  218 	    (&set->ps[(*pos)++], &p->email, NULL) == -1)
  219 		exit(EXIT_FAILURE);
  220 	if (sqlbox_parm_string_alloc
  221 	    (&set->ps[(*pos)++], &p->hash, NULL) == -1)
  222 		exit(EXIT_FAILURE);
  223 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->id) == -1)
  224 		exit(EXIT_FAILURE);
  225 }
  226 
  227 static void
  228 db_user_fill_r(struct ort *ctx, struct user *p,
  229 	const struct sqlbox_parmset *res, size_t *pos)
  230 {
  231 	size_t i = 0;
  232 
  233 	if (pos == NULL)
  234 		pos = &i;
  235 	db_user_fill(ctx, p, res, pos);
  236 }
  237 
  238 /*
  239  * Free resources from "p" and all nested objects.
  240  * Does not free the "p" pointer itself.
  241  * Has no effect if "p" is NULL.
  242  */
  243 static void
  244 db_user_unfill(struct user *p)
  245 {
  246 	if (p == NULL)
  247 		return;
  248 	free(p->email);
  249 	free(p->hash);
  250 }
  251 
  252 static void
  253 db_user_unfill_r(struct user *p)
  254 {
  255 	if (p == NULL)
  256 		return;
  257 	db_user_unfill(p);
  258 }
  259 
  260 void
  261 db_user_free(struct user *p)
  262 {
  263 	db_user_unfill_r(p);
  264 	free(p);
  265 }
  266 
  267 void
  268 json_user_data(struct kjsonreq *r, const struct user *p)
  269 {
  270 	kjson_putstringp(r, "email", p->email);
  271 
  272 	/* Omitting hash: is a password hash. */
  273 
  274 	kjson_putintp(r, "id", p->id);
  275 }
  276 
  277 void
  278 json_user_obj(struct kjsonreq *r, const struct user *p)
  279 {
  280 	kjson_objp_open(r, "user");
  281 	json_user_data(r, p);
  282 	kjson_obj_close(r);
  283 }
  284 
  285 int
  286 valid_user_email(struct kpair *p)
  287 {
  288 	if (!kvalid_string(p))
  289 		return 0;
  290 	if (p->valsz <= 3)
  291 		return 0;
  292 	if (p->valsz > 128)
  293 		return 0;
  294 	return 1;
  295 }
  296 
  297 int
  298 valid_user_hash(struct kpair *p)
  299 {
  300 	if (!kvalid_string(p))
  301 		return 0;
  302 	if (p->valsz <= 6)
  303 		return 0;
  304 	if (p->valsz > 128)
  305 		return 0;
  306 	return 1;
  307 }
  308 
  309 int
  310 valid_user_id(struct kpair *p)
  311 {
  312 	if (!kvalid_int(p))
  313 		return 0;
  314 	return 1;
  315 }
  316 
  317 struct user *
  318 db_user_get_creds(struct ort *ctx, const char *v1, const char *v2)
  319 {
  320 	struct user *p = NULL;
  321 	const struct sqlbox_parmset *res;
  322 	struct sqlbox *db = ctx->db;
  323 	struct sqlbox_parm parms[1];
  324 
  325 	memset(parms, 0, sizeof(parms));
  326 	parms[0].sparm = v1;
  327 	parms[0].type = SQLBOX_PARM_STRING;
  328 
  329 	if (!sqlbox_prepare_bind_async
  330 	    (db, 0, STMT_USER_BY_SEARCH_0, 1, parms, 0))
  331 		exit(EXIT_FAILURE);
  332 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  333 		p = malloc(sizeof(struct user));
  334 		if (p == NULL) {
  335 			perror(NULL);
  336 			exit(EXIT_FAILURE);
  337 		}
  338 		db_user_fill_r(ctx, p, res, NULL);
  339 		if (crypt_checkpass(v2, p->hash) == -1) {
  340 			db_user_free(p);
  341 			p = NULL;
  342 		}
  343 	}
  344 	if (res == NULL)
  345 		exit(EXIT_FAILURE);
  346 	if (!sqlbox_finalise(db, 0))
  347 		exit(EXIT_FAILURE);
  348 	return p;
  349 }
  350 
  351 /*
  352  * Fill in a sess from an open statement "stmt".
  353  * This starts grabbing results from "pos", which may be NULL to start 
  354  * from zero.
  355  * This follows DB_SCHEMA_SESS's order for columns.
  356  */
  357 static void
  358 db_sess_fill(struct ort *ctx, struct sess *p, const struct sqlbox_parmset *set, size_t *pos)
  359 {
  360 	size_t i = 0;
  361 
  362 	if (pos == NULL)
  363 		pos = &i;
  364 	memset(p, 0, sizeof(*p));
  365 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->userid) == -1)
  366 		exit(EXIT_FAILURE);
  367 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->token) == -1)
  368 		exit(EXIT_FAILURE);
  369 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->id) == -1)
  370 		exit(EXIT_FAILURE);
  371 }
  372 
  373 static void
  374 db_sess_fill_r(struct ort *ctx, struct sess *p,
  375 	const struct sqlbox_parmset *res, size_t *pos)
  376 {
  377 	size_t i = 0;
  378 
  379 	if (pos == NULL)
  380 		pos = &i;
  381 	db_sess_fill(ctx, p, res, pos);
  382 	db_user_fill_r(ctx, &p->user, res, pos);
  383 }
  384 
  385 /*
  386  * Free resources from "p" and all nested objects.
  387  * Does not free the "p" pointer itself.
  388  * Has no effect if "p" is NULL.
  389  */
  390 static void
  391 db_sess_unfill(struct sess *p)
  392 {
  393 	if (p == NULL)
  394 		return;
  395 }
  396 
  397 static void
  398 db_sess_unfill_r(struct sess *p)
  399 {
  400 	if (p == NULL)
  401 		return;
  402 	db_sess_unfill(p);
  403 	db_user_unfill_r(&p->user);
  404 }
  405 
  406 void
  407 db_sess_free(struct sess *p)
  408 {
  409 	db_sess_unfill_r(p);
  410 	free(p);
  411 }
  412 
  413 void
  414 json_sess_data(struct kjsonreq *r, const struct sess *p)
  415 {
  416 	kjson_objp_open(r, "user");
  417 	json_user_data(r, &p->user);
  418 	kjson_obj_close(r);
  419 	kjson_putintp(r, "userid", p->userid);
  420 	kjson_putintp(r, "token", p->token);
  421 	kjson_putintp(r, "id", p->id);
  422 }
  423 
  424 void
  425 json_sess_obj(struct kjsonreq *r, const struct sess *p)
  426 {
  427 	kjson_objp_open(r, "sess");
  428 	json_sess_data(r, p);
  429 	kjson_obj_close(r);
  430 }
  431 
  432 int
  433 valid_sess_userid(struct kpair *p)
  434 {
  435 	if (!kvalid_int(p))
  436 		return 0;
  437 	return 1;
  438 }
  439 
  440 int
  441 valid_sess_token(struct kpair *p)
  442 {
  443 	if (!kvalid_int(p))
  444 		return 0;
  445 	return 1;
  446 }
  447 
  448 int
  449 valid_sess_id(struct kpair *p)
  450 {
  451 	if (!kvalid_int(p))
  452 		return 0;
  453 	return 1;
  454 }
  455 
  456 struct sess *
  457 db_sess_get_creds(struct ort *ctx, int64_t v1, int64_t v2)
  458 {
  459 	struct sess *p = NULL;
  460 	const struct sqlbox_parmset *res;
  461 	struct sqlbox *db = ctx->db;
  462 	struct sqlbox_parm parms[2];
  463 
  464 	memset(parms, 0, sizeof(parms));
  465 	parms[0].iparm = v1;
  466 	parms[0].type = SQLBOX_PARM_INT;
  467 	parms[1].iparm = v2;
  468 	parms[1].type = SQLBOX_PARM_INT;
  469 
  470 	if (!sqlbox_prepare_bind_async
  471 	    (db, 0, STMT_SESS_BY_SEARCH_0, 2, parms, 0))
  472 		exit(EXIT_FAILURE);
  473 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  474 		p = malloc(sizeof(struct sess));
  475 		if (p == NULL) {
  476 			perror(NULL);
  477 			exit(EXIT_FAILURE);
  478 		}
  479 		db_sess_fill_r(ctx, p, res, NULL);
  480 	}
  481 	if (res == NULL)
  482 		exit(EXIT_FAILURE);
  483 	if (!sqlbox_finalise(db, 0))
  484 		exit(EXIT_FAILURE);
  485 	return p;
  486 }
  487 
  488 int
  489 db_sess_delete_id(struct ort *ctx, int64_t v1)
  490 {
  491 	enum sqlbox_code c;
  492 	struct sqlbox *db = ctx->db;
  493 	struct sqlbox_parm parms[1];
  494 
  495 	memset(parms, 0, sizeof(parms));
  496 	parms[0].iparm = v1;
  497 	parms[0].type = SQLBOX_PARM_INT;
  498 
  499 	c = sqlbox_exec
  500 		(db, 0, STMT_SESS_DELETE_0,
  501 		 1, parms, SQLBOX_STMT_CONSTRAINT);
  502 	if (c == SQLBOX_CODE_ERROR)
  503 		exit(EXIT_FAILURE);
  504 	return (c == SQLBOX_CODE_OK) ? 1 : 0;
  505 }
  506