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