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