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 "rbac-ex2.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_SESSION_BY_UNIQUE_id,
   30 	STMT_SESSION_BY_SEARCH_0,
   31 	STMT_SESSION_INSERT,
   32 	STMT_SESSION_DELETE_0,
   33 	STMT__MAX
   34 };
   35 
   36 /*
   37  * Definition of our opaque "ort", which contains role information.
   38  */
   39 struct	ort {
   40 	/* Hidden database connection */
   41 	struct sqlbox *db;
   42 	/* Current RBAC role. */
   43 	enum ort_role role;
   44 };
   45 
   46 /*
   47  * A saved role state attached to generated objects.
   48  * We'll use this to make sure that we shouldn't export data that we've 
   49  * kept unexported in a given role (at the time of acquisition).
   50  */
   51 struct	ort_store {
   52 	/* Role at the time of acquisition. */
   53 	enum ort_role role;
   54 };
   55 
   56 /*
   57  * Define our table columns.
   58  * Since we're using roles, this is all internal to the source and not 
   59  * exported.
   60  */
   61 #define DB_SCHEMA_USER(_x) \
   62 	#_x ".email" "," \
   63 	#_x ".hash" "," \
   64 	#_x ".id"
   65 #define DB_SCHEMA_SESSION(_x) \
   66 	#_x ".userid" "," \
   67 	#_x ".id"
   68 
   69 /*
   70  * Our full set of SQL statements.
   71  * We define these beforehand because that's how sqlbox(3) handles 
   72  * statement generation.
   73  * Notice the "AS" part: this allows for multiple inner joins without 
   74  * ambiguity.
   75  */
   76 static	const char *const stmts[STMT__MAX] = {
   77 	/* STMT_USER_BY_UNIQUE_email */
   78 	"SELECT " DB_SCHEMA_USER(user) " FROM user WHERE user.email = ?",
   79 	/* STMT_USER_BY_UNIQUE_id */
   80 	"SELECT " DB_SCHEMA_USER(user) " FROM user WHERE user.id = ?",
   81 	/* STMT_USER_BY_SEARCH_0 */
   82 	"SELECT " DB_SCHEMA_USER(user) " FROM user "
   83 		"WHERE user.email = ?",
   84 	/* STMT_SESSION_BY_UNIQUE_id */
   85 	"SELECT " DB_SCHEMA_SESSION(session) "," DB_SCHEMA_USER(_a) " FROM session "
   86 		"INNER JOIN user AS _a ON _a.id=session.userid "
   87 		"WHERE session.id = ?",
   88 	/* STMT_SESSION_BY_SEARCH_0 */
   89 	"SELECT " DB_SCHEMA_SESSION(session) "," DB_SCHEMA_USER(_a) " FROM session "
   90 		"INNER JOIN user AS _a ON _a.id=session.userid "
   91 		"WHERE session.id = ?",
   92 	/* STMT_SESSION_INSERT */
   93 	"INSERT INTO session (userid) VALUES (?)",
   94 	/* STMT_SESSION_DELETE_0 */
   95 	"DELETE FROM session WHERE id = ?",
   96 };
   97 
   98 const struct kvalid valid_keys[VALID__MAX] = {
   99 	{ valid_user_email, "user-email" },
  100 	{ valid_user_hash, "user-hash" },
  101 	{ valid_user_id, "user-id" },
  102 	{ valid_session_userid, "session-userid" },
  103 	{ valid_session_id, "session-id" },
  104 };
  105 
  106 /*
  107  * Finally, all of the functions we'll use.
  108  */
  109 
  110 void
  111 db_trans_open(struct ort *ctx, size_t id, int mode)
  112 {
  113 	struct sqlbox *db = ctx->db;
  114 	int c;
  115 
  116 	if (mode < 0)
  117 		c = sqlbox_trans_exclusive(db, 0, id);
  118 	else if (mode > 0)
  119 		c = sqlbox_trans_immediate(db, 0, id);
  120 	else
  121 		c = sqlbox_trans_deferred(db, 0, id);
  122 	if (!c)
  123 		exit(EXIT_FAILURE);
  124 }
  125 
  126 void
  127 db_trans_rollback(struct ort *ctx, size_t id)
  128 {
  129 	struct sqlbox *db = ctx->db;
  130 
  131 	if (!sqlbox_trans_rollback(db, 0, id))
  132 		exit(EXIT_FAILURE);
  133 }
  134 
  135 void
  136 db_trans_commit(struct ort *ctx, size_t id)
  137 {
  138 	struct sqlbox *db = ctx->db;
  139 
  140 	if (!sqlbox_trans_commit(db, 0, id))
  141 		exit(EXIT_FAILURE);
  142 }
  143 
  144 void
  145 db_logging_data(struct ort *ort, const void *arg, size_t sz)
  146 {
  147 
  148 	if (!sqlbox_msg_set_dat(ort->db, arg, sz))
  149 		exit(EXIT_FAILURE);
  150 }
  151 
  152 struct ort *
  153 db_open(const char *file)
  154 {
  155 
  156 	return db_open_logging(file, NULL, NULL, NULL);
  157 }
  158 
  159 struct ort *
  160 db_open_logging(const char *file,
  161 	void (*log)(const char *, void *),
  162 	void (*log_short)(const char *, ...), void *log_arg)
  163 {
  164 	size_t i;
  165 	struct ort *ctx = NULL;
  166 	struct sqlbox_cfg cfg;
  167 	struct sqlbox *db = NULL;
  168 	struct sqlbox_pstmt pstmts[STMT__MAX];
  169 	struct sqlbox_src srcs[1] = {
  170 		{ .fname = (char *)file,
  171 		  .mode = SQLBOX_SRC_RW }
  172 	};
  173 	struct sqlbox_role_hier *hier = NULL;
  174 
  175 	memset(&cfg, 0, sizeof(struct sqlbox_cfg));
  176 	cfg.msg.func = log;
  177 	cfg.msg.func_short = log_short;
  178 	cfg.msg.dat = log_arg;
  179 	cfg.srcs.srcs = srcs;
  180 	cfg.srcs.srcsz = 1;
  181 	cfg.stmts.stmts = pstmts;
  182 	cfg.stmts.stmtsz = STMT__MAX;
  183 
  184 	for (i = 0; i < STMT__MAX; i++)
  185 		pstmts[i].stmt = (char *)stmts[i];
  186 
  187 	ctx = malloc(sizeof(struct ort));
  188 	if (ctx == NULL)
  189 		goto err;
  190 
  191 	hier = sqlbox_role_hier_alloc(4);
  192 	if (hier == NULL)
  193 		goto err;
  194 
  195 	/* Assign roles. */
  196 
  197 	if (!sqlbox_role_hier_sink(hier, ROLE_none))
  198 		goto err;
  199 	if (!sqlbox_role_hier_start(hier, ROLE_default))
  200 		goto err;
  201 	if (!sqlbox_role_hier_src(hier, ROLE_default, 0))
  202 		goto err;
  203 
  204 	/* White-listing fields and operations for structure "user". */
  205 
  206 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_USER_BY_UNIQUE_email))
  207 		goto err;
  208 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_USER_BY_UNIQUE_email))
  209 		goto err;
  210 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_USER_BY_UNIQUE_id))
  211 		goto err;
  212 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_USER_BY_UNIQUE_id))
  213 		goto err;
  214 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_USER_BY_SEARCH_0))
  215 		goto err;
  216 
  217 	/* White-listing fields and operations for structure "session". */
  218 
  219 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_SESSION_BY_UNIQUE_id))
  220 		goto err;
  221 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_SESSION_BY_UNIQUE_id))
  222 		goto err;
  223 	if (!sqlbox_role_hier_stmt(hier, ROLE_default, STMT_SESSION_BY_SEARCH_0))
  224 		goto err;
  225 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_SESSION_BY_SEARCH_0))
  226 		goto err;
  227 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_SESSION_BY_SEARCH_0))
  228 		goto err;
  229 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_SESSION_INSERT))
  230 		goto err;
  231 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_SESSION_INSERT))
  232 		goto err;
  233 	if (!sqlbox_role_hier_stmt(hier, ROLE_user, STMT_SESSION_DELETE_0))
  234 		goto err;
  235 	if (!sqlbox_role_hier_stmt(hier, ROLE_admin, STMT_SESSION_DELETE_0))
  236 		goto err;
  237 
  238 	if (!sqlbox_role_hier_gen(hier, &cfg.roles, ROLE_default))
  239 		goto err;
  240 
  241 	if ((db = sqlbox_alloc(&cfg)) == NULL)
  242 		goto err;
  243 	ctx->db = db;
  244 	ctx->role = ROLE_default;
  245 
  246 	sqlbox_role_hier_gen_free(&cfg.roles);
  247 	sqlbox_role_hier_free(hier);
  248 	hier = NULL;
  249 
  250 	/*
  251 	 * Now actually open the database.
  252 	 * If this succeeds, then we're good to go.
  253 	 */
  254 
  255 	if (sqlbox_open_async(db, 0))
  256 		return ctx;
  257 err:
  258 	sqlbox_role_hier_gen_free(&cfg.roles);
  259 	sqlbox_role_hier_free(hier);
  260 	sqlbox_free(db);
  261 	free(ctx);
  262 	return NULL;
  263 }
  264 
  265 void
  266 db_close(struct ort *p)
  267 {
  268 	if (p == NULL)
  269 		return;
  270 	sqlbox_free(p->db);
  271 	free(p);
  272 }
  273 
  274 void
  275 db_role(struct ort *ctx, enum ort_role r)
  276 {
  277 	if (!sqlbox_role(ctx->db, r))
  278 		exit(EXIT_FAILURE);
  279 	if (r == ctx->role)
  280 		return;
  281 	if (ctx->role == ROLE_none)
  282 		abort();
  283 
  284 	switch (ctx->role) {
  285 	case ROLE_default:
  286 		ctx->role = r;
  287 		return;
  288 	case ROLE_user:
  289 		abort();
  290 		/* NOTREACHED */
  291 	case ROLE_admin:
  292 		abort();
  293 		/* NOTREACHED */
  294 	default:
  295 		abort();
  296 	}
  297 }
  298 
  299 enum ort_role
  300 db_role_current(struct ort *ctx)
  301 {
  302 	return ctx->role;
  303 }
  304 
  305 enum ort_role
  306 db_role_stored(struct ort_store *s)
  307 {
  308 	return s->role;
  309 }
  310 
  311 /*
  312  * Fill in a user from an open statement "stmt".
  313  * This starts grabbing results from "pos", which may be NULL to start 
  314  * from zero.
  315  * This follows DB_SCHEMA_USER's order for columns.
  316  */
  317 static void
  318 db_user_fill(struct ort *ctx, struct user *p, const struct sqlbox_parmset *set, size_t *pos)
  319 {
  320 	size_t i = 0;
  321 
  322 	if (pos == NULL)
  323 		pos = &i;
  324 	memset(p, 0, sizeof(*p));
  325 	if (sqlbox_parm_string_alloc
  326 	    (&set->ps[(*pos)++], &p->email, NULL) == -1)
  327 		exit(EXIT_FAILURE);
  328 	if (sqlbox_parm_string_alloc
  329 	    (&set->ps[(*pos)++], &p->hash, NULL) == -1)
  330 		exit(EXIT_FAILURE);
  331 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->id) == -1)
  332 		exit(EXIT_FAILURE);
  333 	p->priv_store = malloc(sizeof(struct ort_store));
  334 	if (p->priv_store == NULL) {
  335 		perror(NULL);
  336 		exit(EXIT_FAILURE);
  337 	}
  338 	p->priv_store->role = ctx->role;
  339 }
  340 
  341 static void
  342 db_user_fill_r(struct ort *ctx, struct user *p,
  343 	const struct sqlbox_parmset *res, size_t *pos)
  344 {
  345 	size_t i = 0;
  346 
  347 	if (pos == NULL)
  348 		pos = &i;
  349 	db_user_fill(ctx, p, res, pos);
  350 }
  351 
  352 /*
  353  * Free resources from "p" and all nested objects.
  354  * Does not free the "p" pointer itself.
  355  * Has no effect if "p" is NULL.
  356  */
  357 static void
  358 db_user_unfill(struct user *p)
  359 {
  360 	if (p == NULL)
  361 		return;
  362 	free(p->email);
  363 	free(p->hash);
  364 	free(p->priv_store);
  365 }
  366 
  367 static void
  368 db_user_unfill_r(struct user *p)
  369 {
  370 	if (p == NULL)
  371 		return;
  372 	db_user_unfill(p);
  373 }
  374 
  375 void
  376 db_user_free(struct user *p)
  377 {
  378 	db_user_unfill_r(p);
  379 	free(p);
  380 }
  381 
  382 void
  383 json_user_data(struct kjsonreq *r, const struct user *p)
  384 {
  385 	kjson_putstringp(r, "email", p->email);
  386 
  387 	/* Omitting hash: is a password hash. */
  388 
  389 	kjson_putintp(r, "id", p->id);
  390 }
  391 
  392 void
  393 json_user_obj(struct kjsonreq *r, const struct user *p)
  394 {
  395 	kjson_objp_open(r, "user");
  396 	json_user_data(r, p);
  397 	kjson_obj_close(r);
  398 }
  399 
  400 int
  401 valid_user_email(struct kpair *p)
  402 {
  403 	if (!kvalid_email(p))
  404 		return 0;
  405 	return 1;
  406 }
  407 
  408 int
  409 valid_user_hash(struct kpair *p)
  410 {
  411 	if (!kvalid_string(p))
  412 		return 0;
  413 	return 1;
  414 }
  415 
  416 int
  417 valid_user_id(struct kpair *p)
  418 {
  419 	if (!kvalid_int(p))
  420 		return 0;
  421 	return 1;
  422 }
  423 
  424 struct user *
  425 db_user_get_creds(struct ort *ctx, const char *v1, const char *v2)
  426 {
  427 	struct user *p = NULL;
  428 	const struct sqlbox_parmset *res;
  429 	struct sqlbox *db = ctx->db;
  430 	struct sqlbox_parm parms[1];
  431 
  432 	memset(parms, 0, sizeof(parms));
  433 	parms[0].sparm = v1;
  434 	parms[0].type = SQLBOX_PARM_STRING;
  435 
  436 	if (!sqlbox_prepare_bind_async
  437 	    (db, 0, STMT_USER_BY_SEARCH_0, 1, parms, 0))
  438 		exit(EXIT_FAILURE);
  439 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  440 		p = malloc(sizeof(struct user));
  441 		if (p == NULL) {
  442 			perror(NULL);
  443 			exit(EXIT_FAILURE);
  444 		}
  445 		db_user_fill_r(ctx, p, res, NULL);
  446 		if (crypt_checkpass(v2, p->hash) == -1) {
  447 			db_user_free(p);
  448 			p = NULL;
  449 		}
  450 	}
  451 	if (res == NULL)
  452 		exit(EXIT_FAILURE);
  453 	if (!sqlbox_finalise(db, 0))
  454 		exit(EXIT_FAILURE);
  455 	return p;
  456 }
  457 
  458 /*
  459  * Fill in a session from an open statement "stmt".
  460  * This starts grabbing results from "pos", which may be NULL to start 
  461  * from zero.
  462  * This follows DB_SCHEMA_SESSION's order for columns.
  463  */
  464 static void
  465 db_session_fill(struct ort *ctx, struct session *p, const struct sqlbox_parmset *set, size_t *pos)
  466 {
  467 	size_t i = 0;
  468 
  469 	if (pos == NULL)
  470 		pos = &i;
  471 	memset(p, 0, sizeof(*p));
  472 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->userid) == -1)
  473 		exit(EXIT_FAILURE);
  474 	if (sqlbox_parm_int(&set->ps[(*pos)++], &p->id) == -1)
  475 		exit(EXIT_FAILURE);
  476 	p->priv_store = malloc(sizeof(struct ort_store));
  477 	if (p->priv_store == NULL) {
  478 		perror(NULL);
  479 		exit(EXIT_FAILURE);
  480 	}
  481 	p->priv_store->role = ctx->role;
  482 }
  483 
  484 static void
  485 db_session_fill_r(struct ort *ctx, struct session *p,
  486 	const struct sqlbox_parmset *res, size_t *pos)
  487 {
  488 	size_t i = 0;
  489 
  490 	if (pos == NULL)
  491 		pos = &i;
  492 	db_session_fill(ctx, p, res, pos);
  493 	db_user_fill_r(ctx, &p->user, res, pos);
  494 }
  495 
  496 /*
  497  * Free resources from "p" and all nested objects.
  498  * Does not free the "p" pointer itself.
  499  * Has no effect if "p" is NULL.
  500  */
  501 static void
  502 db_session_unfill(struct session *p)
  503 {
  504 	if (p == NULL)
  505 		return;
  506 	free(p->priv_store);
  507 }
  508 
  509 static void
  510 db_session_unfill_r(struct session *p)
  511 {
  512 	if (p == NULL)
  513 		return;
  514 	db_session_unfill(p);
  515 	db_user_unfill_r(&p->user);
  516 }
  517 
  518 void
  519 db_session_free(struct session *p)
  520 {
  521 	db_session_unfill_r(p);
  522 	free(p);
  523 }
  524 
  525 int64_t
  526 db_session_insert(struct ort *ctx, int64_t v1)
  527 {
  528 	int rc;
  529 	int64_t id = -1;
  530 	struct sqlbox *db = ctx->db;
  531 	struct sqlbox_parm parms[1];
  532 
  533 	memset(parms, 0, sizeof(parms));
  534 	parms[0].iparm = v1;
  535 	parms[0].type = SQLBOX_PARM_INT;
  536 
  537 	rc = sqlbox_exec(db, 0, STMT_SESSION_INSERT, 
  538 	     1, parms, SQLBOX_STMT_CONSTRAINT);
  539 	if (rc == SQLBOX_CODE_ERROR)
  540 		exit(EXIT_FAILURE);
  541 	else if (rc != SQLBOX_CODE_OK)
  542 		return (-1);
  543 	if (!sqlbox_lastid(db, 0, &id))
  544 		exit(EXIT_FAILURE);
  545 	return id;
  546 }
  547 
  548 void
  549 json_session_data(struct kjsonreq *r, const struct session *p)
  550 {
  551 	kjson_objp_open(r, "user");
  552 	json_user_data(r, &p->user);
  553 	kjson_obj_close(r);
  554 	kjson_putintp(r, "userid", p->userid);
  555 	kjson_putintp(r, "id", p->id);
  556 }
  557 
  558 void
  559 json_session_obj(struct kjsonreq *r, const struct session *p)
  560 {
  561 	kjson_objp_open(r, "session");
  562 	json_session_data(r, p);
  563 	kjson_obj_close(r);
  564 }
  565 
  566 int
  567 valid_session_userid(struct kpair *p)
  568 {
  569 	if (!kvalid_int(p))
  570 		return 0;
  571 	return 1;
  572 }
  573 
  574 int
  575 valid_session_id(struct kpair *p)
  576 {
  577 	if (!kvalid_int(p))
  578 		return 0;
  579 	return 1;
  580 }
  581 
  582 struct session *
  583 db_session_get_id(struct ort *ctx, int64_t v1)
  584 {
  585 	struct session *p = NULL;
  586 	const struct sqlbox_parmset *res;
  587 	struct sqlbox *db = ctx->db;
  588 	struct sqlbox_parm parms[1];
  589 
  590 	memset(parms, 0, sizeof(parms));
  591 	parms[0].iparm = v1;
  592 	parms[0].type = SQLBOX_PARM_INT;
  593 
  594 	if (!sqlbox_prepare_bind_async
  595 	    (db, 0, STMT_SESSION_BY_SEARCH_0, 1, parms, 0))
  596 		exit(EXIT_FAILURE);
  597 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  598 		p = malloc(sizeof(struct session));
  599 		if (p == NULL) {
  600 			perror(NULL);
  601 			exit(EXIT_FAILURE);
  602 		}
  603 		db_session_fill_r(ctx, p, res, NULL);
  604 	}
  605 	if (res == NULL)
  606 		exit(EXIT_FAILURE);
  607 	if (!sqlbox_finalise(db, 0))
  608 		exit(EXIT_FAILURE);
  609 	return p;
  610 }
  611 
  612 int
  613 db_session_delete_by_id_eq(struct ort *ctx, int64_t v1)
  614 {
  615 	enum sqlbox_code c;
  616 	struct sqlbox *db = ctx->db;
  617 	struct sqlbox_parm parms[1];
  618 
  619 	memset(parms, 0, sizeof(parms));
  620 	parms[0].iparm = v1;
  621 	parms[0].type = SQLBOX_PARM_INT;
  622 
  623 	c = sqlbox_exec
  624 		(db, 0, STMT_SESSION_DELETE_0,
  625 		 1, parms, SQLBOX_STMT_CONSTRAINT);
  626 	if (c == SQLBOX_CODE_ERROR)
  627 		exit(EXIT_FAILURE);
  628 	return (c == SQLBOX_CODE_OK) ? 1 : 0;
  629 }
  630