Annotation of embedaddon/strongswan/src/libimcv/plugins/imv_attestation/attest_db.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2017 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE
! 17:
! 18: #include <stdio.h>
! 19: #include <libgen.h>
! 20: #include <time.h>
! 21:
! 22: #include <tncif_names.h>
! 23:
! 24: #include "attest_db.h"
! 25:
! 26: #include "imcv.h"
! 27: #include "pts/pts_meas_algo.h"
! 28: #include "pts/pts_file_meas.h"
! 29: #include "pts/components/pts_comp_func_name.h"
! 30:
! 31: #define IMA_MAX_NAME_LEN 255
! 32: #define DEVICE_MAX_LEN 20
! 33:
! 34: typedef struct private_attest_db_t private_attest_db_t;
! 35:
! 36: /**
! 37: * Private data of an attest_db_t object.
! 38: */
! 39: struct private_attest_db_t {
! 40:
! 41: /**
! 42: * Public members of attest_db_state_t
! 43: */
! 44: attest_db_t public;
! 45:
! 46: /**
! 47: * Component Functional Name to be queried
! 48: */
! 49: pts_comp_func_name_t *cfn;
! 50:
! 51: /**
! 52: * Primary key of the Component Functional Name to be queried
! 53: */
! 54: int cid;
! 55:
! 56: /**
! 57: * TRUE if Component Functional Name has been set
! 58: */
! 59: bool comp_set;
! 60:
! 61: /**
! 62: * Directory containing the Measurement file to be queried
! 63: */
! 64: char *dir;
! 65:
! 66: /**
! 67: * Primary key of the directory to be queried
! 68: */
! 69: int did;
! 70:
! 71: /**
! 72: * Measurement file to be queried
! 73: */
! 74: char *file;
! 75:
! 76: /**
! 77: * Primary key of measurement file to be queried
! 78: */
! 79: int fid;
! 80:
! 81: /**
! 82: * Directory where file measurement are to be taken
! 83: */
! 84: char *meas_dir;
! 85:
! 86: /**
! 87: * AIK to be queried
! 88: */
! 89: chunk_t key;
! 90:
! 91: /**
! 92: * Primary key of the AIK to be queried
! 93: */
! 94: int kid;
! 95:
! 96: /**
! 97: * TRUE if AIK has been set
! 98: */
! 99: bool key_set;
! 100:
! 101: /**
! 102: * Software package to be queried
! 103: */
! 104: char *package;
! 105:
! 106: /**
! 107: * Primary key of software package to be queried
! 108: */
! 109: int gid;
! 110:
! 111: /**
! 112: * TRUE if package has been set
! 113: */
! 114: bool package_set;
! 115:
! 116: /**
! 117: * Software product to be queried
! 118: */
! 119: char *product;
! 120:
! 121: /**
! 122: * Primary key of software product to be queried
! 123: */
! 124: int pid;
! 125:
! 126: /**
! 127: * TRUE if product has been set
! 128: */
! 129: bool product_set;
! 130:
! 131: /**
! 132: * Software package version to be queried
! 133: */
! 134: char *version;
! 135:
! 136: /**
! 137: * Primary key of software package version to be queried
! 138: */
! 139: int vid;
! 140:
! 141: /**
! 142: * TRUE if version has been set
! 143: */
! 144: bool version_set;
! 145:
! 146: /**
! 147: * TRUE if relative filenames are to be used
! 148: */
! 149: bool relative;
! 150:
! 151: /**
! 152: * TRUE if dates are to be displayed in UTC
! 153: */
! 154: bool utc;
! 155:
! 156: /**
! 157: * Package security or blacklist state
! 158: */
! 159: os_package_state_t package_state;
! 160:
! 161: /**
! 162: * Sequence number for ordering entries
! 163: */
! 164: int seq_no;
! 165:
! 166: /**
! 167: * File measurement hash algorithm
! 168: */
! 169: pts_meas_algorithms_t algo;
! 170:
! 171: /**
! 172: * Optional owner (user/host name)
! 173: */
! 174: char *owner;
! 175:
! 176: /**
! 177: * Attestation database
! 178: */
! 179: database_t *db;
! 180:
! 181: };
! 182:
! 183: char* print_cfn(pts_comp_func_name_t *cfn)
! 184: {
! 185: static char buf[BUF_LEN];
! 186: char flags[8];
! 187: int type, vid, name, qualifier, n;
! 188: enum_name_t *names, *types;
! 189:
! 190: vid = cfn->get_vendor_id(cfn);
! 191: name = cfn->get_name(cfn);
! 192: qualifier = cfn->get_qualifier(cfn);
! 193: n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier);
! 194:
! 195: names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid);
! 196: types = imcv_pts_components->get_qualifier_type_names(imcv_pts_components,
! 197: vid);
! 198: type = imcv_pts_components->get_qualifier(imcv_pts_components, cfn, flags);
! 199: if (names && types)
! 200: {
! 201: n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N",
! 202: pen_names, vid, names, name, flags, types, type);
! 203: }
! 204: return buf;
! 205: }
! 206:
! 207: /**
! 208: * Get the directory separator to append to a path
! 209: */
! 210: static const char* get_separator(const char *path)
! 211: {
! 212: if (streq(path, DIRECTORY_SEPARATOR))
! 213: { /* root directory on Unix file system, no separator */
! 214: return "";
! 215: }
! 216: else
! 217: { /* non-root or Windows path, use system specific separator */
! 218: return DIRECTORY_SEPARATOR;
! 219: }
! 220: }
! 221:
! 222: METHOD(attest_db_t, set_component, bool,
! 223: private_attest_db_t *this, char *comp, bool create)
! 224: {
! 225: enumerator_t *e;
! 226: char *pos1, *pos2;
! 227: int vid, name, qualifier;
! 228: pts_comp_func_name_t *cfn;
! 229:
! 230: if (this->comp_set)
! 231: {
! 232: printf("component has already been set\n");
! 233: return FALSE;
! 234: }
! 235:
! 236: /* parse component string */
! 237: pos1 = strchr(comp, '/');
! 238: pos2 = strchr(comp, '-');
! 239: if (!pos1 || !pos2)
! 240: {
! 241: printf("component string must have the form \"vendor_id/name-qualifier\"\n");
! 242: return FALSE;
! 243: }
! 244: vid = atoi(comp);
! 245: name = atoi(pos1 + 1);
! 246: qualifier = atoi(pos2 + 1);
! 247: cfn = pts_comp_func_name_create(vid, name, qualifier);
! 248:
! 249: e = this->db->query(this->db,
! 250: "SELECT id FROM components "
! 251: "WHERE vendor_id = ? AND name = ? AND qualifier = ?",
! 252: DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT);
! 253: if (e)
! 254: {
! 255: if (e->enumerate(e, &this->cid))
! 256: {
! 257: this->comp_set = TRUE;
! 258: this->cfn = cfn;
! 259: }
! 260: e->destroy(e);
! 261: }
! 262: if (this->comp_set)
! 263: {
! 264: return TRUE;
! 265: }
! 266:
! 267: if (!create)
! 268: {
! 269: printf("component '%s' not found in database\n", print_cfn(cfn));
! 270: cfn->destroy(cfn);
! 271: return FALSE;
! 272: }
! 273:
! 274: /* Add a new database entry */
! 275: this->comp_set = this->db->execute(this->db, &this->cid,
! 276: "INSERT INTO components (vendor_id, name, qualifier) "
! 277: "VALUES (?, ?, ?)",
! 278: DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1;
! 279:
! 280: printf("component '%s' %sinserted into database\n", print_cfn(cfn),
! 281: this->comp_set ? "" : "could not be ");
! 282: if (this->comp_set)
! 283: {
! 284: this->cfn = cfn;
! 285: }
! 286: else
! 287: {
! 288: cfn->destroy(cfn);
! 289: }
! 290: return this->comp_set;
! 291: }
! 292:
! 293: METHOD(attest_db_t, set_cid, bool,
! 294: private_attest_db_t *this, int cid)
! 295: {
! 296: enumerator_t *e;
! 297: int vid, name, qualifier;
! 298:
! 299: if (this->comp_set)
! 300: {
! 301: printf("component has already been set\n");
! 302: return FALSE;
! 303: }
! 304: this->cid = cid;
! 305:
! 306: e = this->db->query(this->db, "SELECT vendor_id, name, qualifier "
! 307: "FROM components WHERE id = ?",
! 308: DB_UINT, cid, DB_INT, DB_INT, DB_INT);
! 309: if (e)
! 310: {
! 311: if (e->enumerate(e, &vid, &name, &qualifier))
! 312: {
! 313: this->cfn = pts_comp_func_name_create(vid, name, qualifier);
! 314: this->comp_set = TRUE;
! 315: }
! 316: else
! 317: {
! 318: printf("no component found with cid %d\n", cid);
! 319: }
! 320: e->destroy(e);
! 321: }
! 322: return this->comp_set;
! 323: }
! 324:
! 325: METHOD(attest_db_t, set_directory, bool,
! 326: private_attest_db_t *this, char *dir, bool create)
! 327: {
! 328: enumerator_t *e;
! 329: int did;
! 330: size_t len;
! 331:
! 332: if (this->did)
! 333: {
! 334: printf("directory has already been set\n");
! 335: return FALSE;
! 336: }
! 337:
! 338: /* remove trailing '/' or '\' character if not root directory */
! 339: len = strlen(dir);
! 340: if (len > 1 && dir[len-1] == DIRECTORY_SEPARATOR[0])
! 341: {
! 342: dir[len-1] = '\0';
! 343: }
! 344: this->dir = strdup(dir);
! 345:
! 346: e = this->db->query(this->db,
! 347: "SELECT id FROM directories WHERE path = ?",
! 348: DB_TEXT, dir, DB_INT);
! 349: if (e)
! 350: {
! 351: if (e->enumerate(e, &did))
! 352: {
! 353: this->did = did;
! 354: }
! 355: e->destroy(e);
! 356: }
! 357: if (this->did)
! 358: {
! 359: return TRUE;
! 360: }
! 361:
! 362: if (!create)
! 363: {
! 364: printf("directory '%s' not found in database\n", dir);
! 365: return FALSE;
! 366: }
! 367:
! 368: /* Add a new database entry */
! 369: if (1 == this->db->execute(this->db, &did,
! 370: "INSERT INTO directories (path) VALUES (?)", DB_TEXT, dir))
! 371: {
! 372: this->did = did;
! 373: }
! 374: printf("directory '%s' %sinserted into database\n", dir,
! 375: this->did ? "" : "could not be ");
! 376:
! 377: return this->did > 0;
! 378: }
! 379:
! 380: METHOD(attest_db_t, set_did, bool,
! 381: private_attest_db_t *this, int did)
! 382: {
! 383: enumerator_t *e;
! 384: char *dir;
! 385:
! 386: if (this->did)
! 387: {
! 388: printf("directory has already been set\n");
! 389: return FALSE;
! 390: }
! 391:
! 392: e = this->db->query(this->db, "SELECT path FROM directories WHERE id = ?",
! 393: DB_UINT, did, DB_TEXT);
! 394: if (e)
! 395: {
! 396: if (e->enumerate(e, &dir))
! 397: {
! 398: this->dir = strdup(dir);
! 399: this->did = did;
! 400: }
! 401: else
! 402: {
! 403: printf("no directory found with did %d\n", did);
! 404: }
! 405: e->destroy(e);
! 406: }
! 407: return this->did > 0;
! 408: }
! 409:
! 410: METHOD(attest_db_t, set_file, bool,
! 411: private_attest_db_t *this, char *file, bool create)
! 412: {
! 413: int fid;
! 414: enumerator_t *e;
! 415:
! 416: if (this->file)
! 417: {
! 418: printf("file has already been set\n");
! 419: return FALSE;
! 420: }
! 421: this->file = strdup(file);
! 422:
! 423: if (!this->did)
! 424: {
! 425: return TRUE;
! 426: }
! 427: e = this->db->query(this->db, "SELECT id FROM files "
! 428: "WHERE dir = ? AND name = ?",
! 429: DB_INT, this->did, DB_TEXT, file, DB_INT);
! 430: if (e)
! 431: {
! 432: if (e->enumerate(e, &fid))
! 433: {
! 434: this->fid = fid;
! 435: }
! 436: e->destroy(e);
! 437: }
! 438: if (this->fid)
! 439: {
! 440: return TRUE;
! 441: }
! 442:
! 443: if (!create)
! 444: {
! 445: printf("file '%s%s%s' not found in database\n",
! 446: this->dir, get_separator(this->dir), file);
! 447: return FALSE;
! 448: }
! 449:
! 450: /* Add a new database entry */
! 451: if (1 == this->db->execute(this->db, &fid,
! 452: "INSERT INTO files (dir, name) VALUES (?, ?)",
! 453: DB_INT, this->did, DB_TEXT, file))
! 454: {
! 455: this->fid = fid;
! 456: }
! 457: printf("file '%s%s%s' %sinserted into database\n", this->dir,
! 458: get_separator(this->dir), file, this->fid ? "" : "could not be ");
! 459:
! 460: return this->fid > 0;
! 461: }
! 462:
! 463: METHOD(attest_db_t, set_fid, bool,
! 464: private_attest_db_t *this, int fid)
! 465: {
! 466: enumerator_t *e;
! 467: int did;
! 468: char *file;
! 469:
! 470: if (this->fid)
! 471: {
! 472: printf("file has already been set\n");
! 473: return FALSE;
! 474: }
! 475:
! 476: e = this->db->query(this->db, "SELECT dir, name FROM files WHERE id = ?",
! 477: DB_UINT, fid, DB_INT, DB_TEXT);
! 478: if (e)
! 479: {
! 480: if (e->enumerate(e, &did, &file))
! 481: {
! 482: if (did)
! 483: {
! 484: set_did(this, did);
! 485: }
! 486: this->file = strdup(file);
! 487: this->fid = fid;
! 488: }
! 489: else
! 490: {
! 491: printf("no file found with fid %d\n", fid);
! 492: }
! 493: e->destroy(e);
! 494: }
! 495: return this->fid > 0;
! 496: }
! 497:
! 498: METHOD(attest_db_t, set_meas_directory, bool,
! 499: private_attest_db_t *this, char *dir)
! 500: {
! 501: size_t len;
! 502:
! 503: /* remove trailing '/' character if not root directory */
! 504: len = strlen(dir);
! 505: if (len > 1 && dir[len-1] == '/')
! 506: {
! 507: dir[len-1] = '\0';
! 508: }
! 509: this->meas_dir = strdup(dir);
! 510:
! 511: return TRUE;
! 512: }
! 513:
! 514: METHOD(attest_db_t, set_key, bool,
! 515: private_attest_db_t *this, chunk_t key, bool create)
! 516: {
! 517: enumerator_t *e;
! 518: char *owner;
! 519:
! 520: if (this->key_set)
! 521: {
! 522: printf("key has already been set\n");
! 523: return FALSE;
! 524: }
! 525: this->key = key;
! 526:
! 527: e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?",
! 528: DB_BLOB, this->key, DB_INT, DB_TEXT);
! 529: if (e)
! 530: {
! 531: if (e->enumerate(e, &this->kid, &owner))
! 532: {
! 533: free(this->owner);
! 534: this->owner = strdup(owner);
! 535: this->key_set = TRUE;
! 536: }
! 537: e->destroy(e);
! 538: }
! 539: if (this->key_set)
! 540: {
! 541: return TRUE;
! 542: }
! 543:
! 544: if (!create)
! 545: {
! 546: printf("key '%#B' not found in database\n", &this->key);
! 547: return FALSE;
! 548: }
! 549:
! 550: /* Add a new database entry */
! 551: if (!this->owner)
! 552: {
! 553: this->owner = strdup("");
! 554: }
! 555: this->key_set = this->db->execute(this->db, &this->kid,
! 556: "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
! 557: DB_BLOB, this->key, DB_TEXT, this->owner) == 1;
! 558:
! 559: printf("key '%#B' %sinserted into database\n", &this->key,
! 560: this->key_set ? "" : "could not be ");
! 561:
! 562: return this->key_set;
! 563:
! 564: };
! 565:
! 566: METHOD(attest_db_t, set_kid, bool,
! 567: private_attest_db_t *this, int kid)
! 568: {
! 569: enumerator_t *e;
! 570: chunk_t key;
! 571: char *owner;
! 572:
! 573: if (this->key_set)
! 574: {
! 575: printf("key has already been set\n");
! 576: return FALSE;
! 577: }
! 578: this->kid = kid;
! 579:
! 580: e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?",
! 581: DB_UINT, kid, DB_BLOB, DB_TEXT);
! 582: if (e)
! 583: {
! 584: if (e->enumerate(e, &key, &owner))
! 585: {
! 586: this->owner = strdup(owner);
! 587: this->key = chunk_clone(key);
! 588: this->key_set = TRUE;
! 589: }
! 590: else
! 591: {
! 592: printf("no key found with kid %d\n", kid);
! 593: }
! 594: e->destroy(e);
! 595: }
! 596: return this->key_set;
! 597:
! 598: };
! 599:
! 600: METHOD(attest_db_t, set_product, bool,
! 601: private_attest_db_t *this, char *product, bool create)
! 602: {
! 603: enumerator_t *e;
! 604:
! 605: if (this->product_set)
! 606: {
! 607: printf("product has already been set\n");
! 608: return FALSE;
! 609: }
! 610: this->product = strdup(product);
! 611:
! 612: e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
! 613: DB_TEXT, product, DB_INT);
! 614: if (e)
! 615: {
! 616: if (e->enumerate(e, &this->pid))
! 617: {
! 618: this->product_set = TRUE;
! 619: }
! 620: e->destroy(e);
! 621: }
! 622: if (this->product_set)
! 623: {
! 624: return TRUE;
! 625: }
! 626:
! 627: if (!create)
! 628: {
! 629: printf("product '%s' not found in database\n", product);
! 630: return FALSE;
! 631: }
! 632:
! 633: /* Add a new database entry */
! 634: this->product_set = this->db->execute(this->db, &this->pid,
! 635: "INSERT INTO products (name) VALUES (?)",
! 636: DB_TEXT, product) == 1;
! 637:
! 638: printf("product '%s' %sinserted into database\n", product,
! 639: this->product_set ? "" : "could not be ");
! 640:
! 641: return this->product_set;
! 642: }
! 643:
! 644: METHOD(attest_db_t, set_pid, bool,
! 645: private_attest_db_t *this, int pid)
! 646: {
! 647: enumerator_t *e;
! 648: char *product;
! 649:
! 650: if (this->product_set)
! 651: {
! 652: printf("product has already been set\n");
! 653: return FALSE;
! 654: }
! 655: this->pid = pid;
! 656:
! 657: e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
! 658: DB_UINT, pid, DB_TEXT);
! 659: if (e)
! 660: {
! 661: if (e->enumerate(e, &product))
! 662: {
! 663: this->product = strdup(product);
! 664: this->product_set = TRUE;
! 665: }
! 666: else
! 667: {
! 668: printf("no product found with pid %d in database\n", pid);
! 669: }
! 670: e->destroy(e);
! 671: }
! 672: return this->product_set;
! 673: }
! 674:
! 675: METHOD(attest_db_t, set_package, bool,
! 676: private_attest_db_t *this, char *package, bool create)
! 677: {
! 678: enumerator_t *e;
! 679:
! 680: if (this->package_set)
! 681: {
! 682: printf("package has already been set\n");
! 683: return FALSE;
! 684: }
! 685: this->package = strdup(package);
! 686:
! 687: e = this->db->query(this->db, "SELECT id FROM packages WHERE name = ?",
! 688: DB_TEXT, package, DB_INT);
! 689: if (e)
! 690: {
! 691: if (e->enumerate(e, &this->gid))
! 692: {
! 693: this->package_set = TRUE;
! 694: }
! 695: e->destroy(e);
! 696: }
! 697: if (this->package_set)
! 698: {
! 699: return TRUE;
! 700: }
! 701:
! 702: if (!create)
! 703: {
! 704: printf("package '%s' not found in database\n", package);
! 705: return FALSE;
! 706: }
! 707:
! 708: /* Add a new database entry */
! 709: this->package_set = this->db->execute(this->db, &this->gid,
! 710: "INSERT INTO packages (name) VALUES (?)",
! 711: DB_TEXT, package) == 1;
! 712:
! 713: printf("package '%s' %sinserted into database\n", package,
! 714: this->package_set ? "" : "could not be ");
! 715:
! 716: return this->package_set;
! 717: }
! 718:
! 719: METHOD(attest_db_t, set_gid, bool,
! 720: private_attest_db_t *this, int gid)
! 721: {
! 722: enumerator_t *e;
! 723: char *package;
! 724:
! 725: if (this->package_set)
! 726: {
! 727: printf("package has already been set\n");
! 728: return FALSE;
! 729: }
! 730: this->gid = gid;
! 731:
! 732: e = this->db->query(this->db, "SELECT name FROM packages WHERE id = ?",
! 733: DB_UINT, gid, DB_TEXT);
! 734: if (e)
! 735: {
! 736: if (e->enumerate(e, &package))
! 737: {
! 738: this->package = strdup(package);
! 739: this->package_set = TRUE;
! 740: }
! 741: else
! 742: {
! 743: printf("no package found with gid %d in database\n", gid);
! 744: }
! 745: e->destroy(e);
! 746: }
! 747: return this->package_set;
! 748: }
! 749:
! 750: METHOD(attest_db_t, set_version, bool,
! 751: private_attest_db_t *this, char *version)
! 752: {
! 753: if (this->version_set)
! 754: {
! 755: printf("version has already been set\n");
! 756: return FALSE;
! 757: }
! 758: this->version = strdup(version);
! 759: this->version_set = TRUE;
! 760:
! 761: return TRUE;
! 762: }
! 763:
! 764:
! 765: METHOD(attest_db_t, set_algo, void,
! 766: private_attest_db_t *this, pts_meas_algorithms_t algo)
! 767: {
! 768: this->algo = algo;
! 769: }
! 770:
! 771: METHOD(attest_db_t, set_relative, void,
! 772: private_attest_db_t *this)
! 773: {
! 774: this->relative = TRUE;
! 775: }
! 776:
! 777: METHOD(attest_db_t, set_package_state, void,
! 778: private_attest_db_t *this, os_package_state_t package_state)
! 779: {
! 780: this->package_state = package_state;
! 781: }
! 782:
! 783: METHOD(attest_db_t, set_sequence, void,
! 784: private_attest_db_t *this, int seq_no)
! 785: {
! 786: this->seq_no = seq_no;
! 787: }
! 788:
! 789: METHOD(attest_db_t, set_owner, void,
! 790: private_attest_db_t *this, char *owner)
! 791: {
! 792: free(this->owner);
! 793: this->owner = strdup(owner);
! 794: }
! 795:
! 796: METHOD(attest_db_t, set_utc, void,
! 797: private_attest_db_t *this)
! 798: {
! 799: this->utc = TRUE;
! 800: }
! 801:
! 802: METHOD(attest_db_t, list_components, void,
! 803: private_attest_db_t *this)
! 804: {
! 805: enumerator_t *e;
! 806: pts_comp_func_name_t *cfn;
! 807: int seq_no, cid, vid, name, qualifier, count = 0;
! 808:
! 809: if (this->kid)
! 810: {
! 811: e = this->db->query(this->db,
! 812: "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier "
! 813: "FROM components AS c "
! 814: "JOIN key_component AS kc ON c.id = kc.component "
! 815: "WHERE kc.key = ? ORDER BY kc.seq_no",
! 816: DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
! 817: if (e)
! 818: {
! 819: while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier))
! 820: {
! 821: cfn = pts_comp_func_name_create(vid, name, qualifier);
! 822: printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn));
! 823: cfn->destroy(cfn);
! 824: count++;
! 825: }
! 826: e->destroy(e);
! 827: printf("%d component%s found for key %#B\n", count,
! 828: (count == 1) ? "" : "s", &this->key);
! 829: }
! 830: }
! 831: else
! 832: {
! 833: e = this->db->query(this->db,
! 834: "SELECT id, vendor_id, name, qualifier FROM components "
! 835: "ORDER BY vendor_id, name, qualifier",
! 836: DB_INT, DB_INT, DB_INT, DB_INT);
! 837: if (e)
! 838: {
! 839: while (e->enumerate(e, &cid, &vid, &name, &qualifier))
! 840: {
! 841: cfn = pts_comp_func_name_create(vid, name, qualifier);
! 842: printf("%4d: %s\n", cid, print_cfn(cfn));
! 843: cfn->destroy(cfn);
! 844: count++;
! 845: }
! 846: e->destroy(e);
! 847: printf("%d component%s found\n", count, (count == 1) ? "" : "s");
! 848: }
! 849: }
! 850: }
! 851:
! 852: METHOD(attest_db_t, list_devices, void,
! 853: private_attest_db_t *this)
! 854: {
! 855: enumerator_t *e, *e_ar;
! 856: chunk_t ar_id_value = chunk_empty;
! 857: char *product, *device, *description;
! 858: time_t timestamp;
! 859: int id, last_id = 0, ar_id = 0, last_ar_id = 0, device_count = 0, trusted;
! 860: int session_id, rec;
! 861: uint32_t ar_id_type;
! 862: u_int tstamp;
! 863:
! 864: e = this->db->query(this->db,
! 865: "SELECT d.id, d.value, d.trusted, d.description, "
! 866: "s.id, s.time, s.identity, s.rec, p.name "
! 867: "FROM devices AS d "
! 868: "JOIN sessions AS s ON d.id = s.device "
! 869: "JOIN products AS p ON p.id = s.product "
! 870: "ORDER BY d.value, s.time DESC", DB_INT, DB_TEXT, DB_INT, DB_TEXT,
! 871: DB_INT, DB_UINT, DB_INT, DB_INT, DB_TEXT);
! 872:
! 873: if (e)
! 874: {
! 875: while (e->enumerate(e, &id, &device, &trusted, &description,
! 876: &session_id, &tstamp, &ar_id, &rec, &product))
! 877: {
! 878: if (id != last_id)
! 879: {
! 880: printf("%4d: %s %s - %s - %s\n", id, trusted ? "+" : "-",
! 881: device, product, description);
! 882: device_count++;
! 883: last_id = id;
! 884: }
! 885: timestamp = tstamp;
! 886: printf("%4d: %T", session_id, ×tamp, this->utc);
! 887: if (ar_id)
! 888: {
! 889: if (ar_id != last_ar_id)
! 890: {
! 891: chunk_free(&ar_id_value);
! 892: e_ar = this->db->query(this->db,
! 893: "SELECT type, value FROM identities "
! 894: "WHERE id = ?", DB_INT, ar_id, DB_INT, DB_BLOB);
! 895: if (e_ar)
! 896: {
! 897: e_ar->enumerate(e_ar, &ar_id_type, &ar_id_value);
! 898: ar_id_value = chunk_clone(ar_id_value);
! 899: e_ar->destroy(e_ar);
! 900: }
! 901: }
! 902: if (ar_id_value.len)
! 903: {
! 904: printf(" %.*s", (int)ar_id_value.len, ar_id_value.ptr);
! 905: }
! 906: last_ar_id = ar_id;
! 907: }
! 908: printf(" - %N\n", TNC_IMV_Action_Recommendation_names, rec);
! 909: }
! 910: e->destroy(e);
! 911: free(ar_id_value.ptr);
! 912:
! 913: printf("%d device%s found\n", device_count,
! 914: (device_count == 1) ? "" : "s");
! 915: }
! 916: }
! 917:
! 918: METHOD(attest_db_t, list_keys, void,
! 919: private_attest_db_t *this)
! 920: {
! 921: enumerator_t *e;
! 922: chunk_t keyid;
! 923: char *owner;
! 924: int kid, count = 0;
! 925:
! 926: if (this->cid)
! 927: {
! 928: e = this->db->query(this->db,
! 929: "SELECT k.id, k.keyid, k.owner FROM keys AS k "
! 930: "JOIN key_component AS kc ON k.id = kc.key "
! 931: "WHERE kc.component = ? ORDER BY k.keyid",
! 932: DB_UINT, this->cid, DB_INT, DB_BLOB, DB_TEXT);
! 933: if (e)
! 934: {
! 935: while (e->enumerate(e, &kid, &keyid, &owner))
! 936: {
! 937: printf("%4d: %#B '%s'\n", kid, &keyid, owner);
! 938: count++;
! 939: }
! 940: e->destroy(e);
! 941: }
! 942: }
! 943: else
! 944: {
! 945: e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys "
! 946: "ORDER BY keyid",
! 947: DB_INT, DB_BLOB, DB_TEXT);
! 948: if (e)
! 949: {
! 950: while (e->enumerate(e, &kid, &keyid, &owner))
! 951: {
! 952: printf("%4d: %#B '%s'\n", kid, &keyid, owner);
! 953: count++;
! 954: }
! 955: e->destroy(e);
! 956: }
! 957: }
! 958:
! 959: printf("%d key%s found", count, (count == 1) ? "" : "s");
! 960: if (this->comp_set)
! 961: {
! 962: printf(" for component '%s'", print_cfn(this->cfn));
! 963: }
! 964: printf("\n");
! 965: }
! 966:
! 967: METHOD(attest_db_t, list_files, void,
! 968: private_attest_db_t *this)
! 969: {
! 970: enumerator_t *e;
! 971: char *dir, *file;
! 972: int did, last_did = 0, fid, count = 0;
! 973:
! 974: if (this->did)
! 975: {
! 976: e = this->db->query(this->db,
! 977: "SELECT id, name FROM files WHERE dir = ? ORDER BY name",
! 978: DB_INT, this->did, DB_INT, DB_TEXT);
! 979: if (e)
! 980: {
! 981: while (e->enumerate(e, &fid, &file))
! 982: {
! 983: printf("%6d: %s\n", fid, file);
! 984: count++;
! 985: }
! 986: e->destroy(e);
! 987: }
! 988: printf("%d file%s found in directory '%s'\n", count,
! 989: (count == 1) ? "" : "s", this->dir);
! 990: }
! 991: else
! 992: {
! 993: e = this->db->query(this->db,
! 994: "SELECT d.id, d.path, f.id, f.name FROM files AS f "
! 995: "JOIN directories AS d ON f.dir = d.id "
! 996: "ORDER BY d.path, f.name",
! 997: DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 998: if (e)
! 999: {
! 1000: while (e->enumerate(e, &did, &dir, &fid, &file))
! 1001: {
! 1002: if (did != last_did)
! 1003: {
! 1004: printf("%6d: %s\n", did, dir);
! 1005: last_did = did;
! 1006: }
! 1007: printf("%6d: %s\n", fid, file);
! 1008: count++;
! 1009: }
! 1010: e->destroy(e);
! 1011: }
! 1012: printf("%d file%s found\n", count, (count == 1) ? "" : "s");
! 1013: }
! 1014: }
! 1015:
! 1016: METHOD(attest_db_t, list_directories, void,
! 1017: private_attest_db_t *this)
! 1018: {
! 1019: enumerator_t *e;
! 1020: char *dir;
! 1021: int did, count = 0;
! 1022:
! 1023: if (this->file)
! 1024: {
! 1025: e = this->db->query(this->db,
! 1026: "SELECT d.id, d.path FROM directories AS d "
! 1027: "JOIN files AS f ON f.dir = d.id WHERE f.name = ? "
! 1028: "ORDER BY path", DB_TEXT, this->file, DB_INT, DB_TEXT);
! 1029: if (e)
! 1030: {
! 1031: while (e->enumerate(e, &did, &dir))
! 1032: {
! 1033: printf("%4d: %s\n", did, dir);
! 1034: count++;
! 1035: }
! 1036: e->destroy(e);
! 1037: }
! 1038: printf("%d director%s found containing file '%s'\n", count,
! 1039: (count == 1) ? "y" : "ies", this->file);
! 1040: }
! 1041: else
! 1042: {
! 1043: e = this->db->query(this->db,
! 1044: "SELECT id, path FROM directories ORDER BY path",
! 1045: DB_INT, DB_TEXT);
! 1046: if (e)
! 1047: {
! 1048: while (e->enumerate(e, &did, &dir))
! 1049: {
! 1050: printf("%4d: %s\n", did, dir);
! 1051: count++;
! 1052: }
! 1053: e->destroy(e);
! 1054: }
! 1055: printf("%d director%s found\n", count, (count == 1) ? "y" : "ies");
! 1056: }
! 1057: }
! 1058:
! 1059: METHOD(attest_db_t, list_packages, void,
! 1060: private_attest_db_t *this)
! 1061: {
! 1062: enumerator_t *e;
! 1063: char *package, *version;
! 1064: os_package_state_t package_state;
! 1065: int blacklist, security, gid, gid_old = 0, spaces, count = 0, t;
! 1066: time_t timestamp;
! 1067:
! 1068: if (this->pid)
! 1069: {
! 1070: e = this->db->query(this->db,
! 1071: "SELECT p.id, p.name, "
! 1072: "v.release, v.security, v.blacklist, v.time "
! 1073: "FROM packages AS p JOIN versions AS v ON v.package = p.id "
! 1074: "WHERE v.product = ? ORDER BY p.name, v.release",
! 1075: DB_INT, this->pid,
! 1076: DB_INT, DB_TEXT, DB_TEXT, DB_INT, DB_INT, DB_INT);
! 1077: if (e)
! 1078: {
! 1079: while (e->enumerate(e, &gid, &package,
! 1080: &version, &security, &blacklist, &t))
! 1081: {
! 1082: if (gid != gid_old)
! 1083: {
! 1084: printf("%5d: %s,", gid, package);
! 1085: gid_old = gid;
! 1086: }
! 1087: else
! 1088: {
! 1089: spaces = 8 + strlen(package);
! 1090: while (spaces--)
! 1091: {
! 1092: printf(" ");
! 1093: }
! 1094: }
! 1095: timestamp = t;
! 1096: if (blacklist)
! 1097: {
! 1098: package_state = OS_PACKAGE_STATE_BLACKLIST;
! 1099: }
! 1100: else
! 1101: {
! 1102: package_state = security ? OS_PACKAGE_STATE_SECURITY :
! 1103: OS_PACKAGE_STATE_UPDATE;
! 1104: }
! 1105: printf(" %T (%s)%N\n", ×tamp, this->utc, version,
! 1106: os_package_state_names, package_state);
! 1107: count++;
! 1108: }
! 1109: e->destroy(e);
! 1110: }
! 1111: }
! 1112: else
! 1113: {
! 1114: e = this->db->query(this->db, "SELECT id, name FROM packages "
! 1115: "ORDER BY name",
! 1116: DB_INT, DB_TEXT);
! 1117: if (e)
! 1118: {
! 1119: while (e->enumerate(e, &gid, &package))
! 1120: {
! 1121: printf("%4d: %s\n", gid, package);
! 1122: count++;
! 1123: }
! 1124: e->destroy(e);
! 1125: }
! 1126: }
! 1127:
! 1128: printf("%d package%s found", count, (count == 1) ? "" : "s");
! 1129: if (this->product_set)
! 1130: {
! 1131: printf(" for product '%s'", this->product);
! 1132: }
! 1133: printf("\n");
! 1134: }
! 1135:
! 1136: METHOD(attest_db_t, list_products, void,
! 1137: private_attest_db_t *this)
! 1138: {
! 1139: enumerator_t *e;
! 1140: char *product;
! 1141: int pid, meas, meta, count = 0;
! 1142:
! 1143: if (this->fid)
! 1144: {
! 1145: e = this->db->query(this->db,
! 1146: "SELECT p.id, p.name, pf.measurement, pf.metadata "
! 1147: "FROM products AS p "
! 1148: "JOIN product_file AS pf ON p.id = pf.product "
! 1149: "WHERE pf.file = ? ORDER BY p.name",
! 1150: DB_UINT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT);
! 1151: if (e)
! 1152: {
! 1153: while (e->enumerate(e, &pid, &product, &meas, &meta))
! 1154: {
! 1155: printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ",
! 1156: product);
! 1157: count++;
! 1158: }
! 1159: e->destroy(e);
! 1160: }
! 1161: }
! 1162: else
! 1163: {
! 1164: e = this->db->query(this->db, "SELECT id, name FROM products "
! 1165: "ORDER BY name",
! 1166: DB_INT, DB_TEXT);
! 1167: if (e)
! 1168: {
! 1169: while (e->enumerate(e, &pid, &product))
! 1170: {
! 1171: printf("%4d: %s\n", pid, product);
! 1172: count++;
! 1173: }
! 1174: e->destroy(e);
! 1175: }
! 1176: }
! 1177:
! 1178: printf("%d product%s found", count, (count == 1) ? "" : "s");
! 1179: if (this->fid)
! 1180: {
! 1181: printf(" for file '%s'", this->file);
! 1182: }
! 1183: printf("\n");
! 1184: }
! 1185:
! 1186: METHOD(attest_db_t, list_hashes, void,
! 1187: private_attest_db_t *this)
! 1188: {
! 1189: enumerator_t *e;
! 1190: char *file, *dir, *product, *hash;
! 1191: int id, fid, fid_old = 0, did, did_old = 0, pid, pid_old = 0, count = 0;
! 1192:
! 1193: if (this->pid && this->fid && this->did)
! 1194: {
! 1195: printf("%6d: %s\n", this->did, this->dir);
! 1196: printf("%6d: %s\n", this->fid, this->file);
! 1197: e = this->db->query(this->db,
! 1198: "SELECT h.id, h.hash FROM file_hashes AS h "
! 1199: "JOIN versions AS v ON h.version = v.id "
! 1200: "WHERE h.algo = ? AND h.file = ? AND v.product = ?",
! 1201: DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid,
! 1202: DB_INT, DB_TEXT);
! 1203: if (e)
! 1204: {
! 1205: while (e->enumerate(e, &id, &hash))
! 1206: {
! 1207: printf("%6d: %s\n", id, hash);
! 1208: count++;
! 1209: }
! 1210: e->destroy(e);
! 1211:
! 1212: printf("%d %N value%s found for product '%s'\n", count,
! 1213: pts_meas_algorithm_names, this->algo,
! 1214: (count == 1) ? "" : "s", this->product);
! 1215: }
! 1216: }
! 1217: else if (this->pid && this->file)
! 1218: {
! 1219: e = this->db->query(this->db,
! 1220: "SELECT h.id, h.hash, f.id, d.id, d.path "
! 1221: "FROM file_hashes AS h "
! 1222: "JOIN files AS f ON h.file = f.id "
! 1223: "JOIN directories AS d ON f.dir = d.id "
! 1224: "JOIN versions AS v ON h.version = v.id "
! 1225: "WHERE h.algo = ? AND v.product = ? AND f.name = ? "
! 1226: "ORDER BY d.path, f.name, h.hash",
! 1227: DB_INT, this->algo, DB_INT, this->pid, DB_TEXT, this->file,
! 1228: DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT);
! 1229: if (e)
! 1230: {
! 1231: while (e->enumerate(e, &id, &hash, &fid, &did, &dir))
! 1232: {
! 1233: if (did != did_old)
! 1234: {
! 1235: printf("%6d: %s\n", did, dir);
! 1236: did_old = did;
! 1237: }
! 1238: if (fid != fid_old)
! 1239: {
! 1240: printf("%6d: %s\n", fid, this->file);
! 1241: fid_old = fid;
! 1242: }
! 1243: printf("%6d: %s\n", id, hash);
! 1244: count++;
! 1245: }
! 1246: e->destroy(e);
! 1247:
! 1248: printf("%d %N value%s found for product '%s'\n", count,
! 1249: pts_meas_algorithm_names, this->algo,
! 1250: (count == 1) ? "" : "s", this->product);
! 1251: }
! 1252: }
! 1253: else if (this->pid && this->did)
! 1254: {
! 1255: printf("%6d: %s\n", this->did, this->dir);
! 1256: e = this->db->query(this->db,
! 1257: "SELECT h.id, h.hash, f.id, f.name "
! 1258: "FROM file_hashes AS h "
! 1259: "JOIN files AS f ON h.file = f.id "
! 1260: "JOIN versions AS v ON h.version = v.id "
! 1261: "WHERE h.algo = ? AND v.product = ? AND f.dir = ? "
! 1262: "ORDER BY f.name, h.hash",
! 1263: DB_INT, this->algo, DB_INT, this->pid, DB_INT, this->did,
! 1264: DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1265: if (e)
! 1266: {
! 1267: while (e->enumerate(e, &id, &hash, &fid, &file))
! 1268: {
! 1269: if (fid != fid_old)
! 1270: {
! 1271: printf("%6d: %s\n", fid, file);
! 1272: fid_old = fid;
! 1273: }
! 1274: printf("%6d: %s\n", id, hash);
! 1275: count++;
! 1276: }
! 1277: e->destroy(e);
! 1278:
! 1279: printf("%d %N value%s found for product '%s'\n", count,
! 1280: pts_meas_algorithm_names, this->algo,
! 1281: (count == 1) ? "" : "s", this->product);
! 1282: }
! 1283: }
! 1284: else if (this->pid)
! 1285: {
! 1286: e = this->db->query(this->db,
! 1287: "SELECT h.id, h.hash, f.id, f.name, d.id, d.path "
! 1288: "FROM file_hashes AS h "
! 1289: "JOIN files AS f ON h.file = f.id "
! 1290: "JOIN directories AS d ON f.dir = d.id "
! 1291: "JOIN versions AS v ON h.version = v.id "
! 1292: "WHERE h.algo = ? AND v.product = ? "
! 1293: "ORDER BY d.path, f.name, h.hash",
! 1294: DB_INT, this->algo, DB_INT, this->pid,
! 1295: DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1296: if (e)
! 1297: {
! 1298: while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir))
! 1299: {
! 1300: if (did != did_old)
! 1301: {
! 1302: printf("%6d: %s\n", did, dir);
! 1303: did_old = did;
! 1304: }
! 1305: if (fid != fid_old)
! 1306: {
! 1307: printf("%6d: %s\n", fid, file);
! 1308: fid_old = fid;
! 1309: }
! 1310: printf("%6d: %s\n", id, hash);
! 1311: count++;
! 1312: }
! 1313: e->destroy(e);
! 1314:
! 1315: printf("%d %N value%s found for product '%s'\n", count,
! 1316: pts_meas_algorithm_names, this->algo,
! 1317: (count == 1) ? "" : "s", this->product);
! 1318: }
! 1319: }
! 1320: else if (this->fid && this->did)
! 1321: {
! 1322: e = this->db->query(this->db,
! 1323: "SELECT h.id, h.hash, p.id, p.name FROM file_hashes AS h "
! 1324: "JOIN versions AS v ON h.version = v.id "
! 1325: "JOIN products AS p ON v.product = p.id "
! 1326: "WHERE h.algo = ? AND h.file = ? "
! 1327: "ORDER BY p.name, h.hash",
! 1328: DB_INT, this->algo, DB_INT, this->fid,
! 1329: DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1330: if (e)
! 1331: {
! 1332: while (e->enumerate(e, &id, &hash, &pid, &product))
! 1333: {
! 1334: if (pid != pid_old)
! 1335: {
! 1336: printf("%6d: %s\n", pid, product);
! 1337: pid_old = pid;
! 1338: }
! 1339: printf("%6d: %s\n", id, hash);
! 1340: count++;
! 1341: }
! 1342: e->destroy(e);
! 1343:
! 1344: printf("%d %N value%s found for file '%s%s%s'\n", count,
! 1345: pts_meas_algorithm_names, this->algo,
! 1346: (count == 1) ? "" : "s", this->dir,
! 1347: get_separator(this->dir), this->file);
! 1348: }
! 1349: }
! 1350: else if (this->file)
! 1351: {
! 1352: e = this->db->query(this->db,
! 1353: "SELECT h.id, h.hash, f.id, d.id, d.path, p.id, p.name "
! 1354: "FROM file_hashes AS h "
! 1355: "JOIN files AS f ON h.file = f.id "
! 1356: "JOIN directories AS d ON f.dir = d.id "
! 1357: "JOIN versions AS v ON h.version = v.id "
! 1358: "JOIN products AS p ON v.product = p.id "
! 1359: "WHERE h.algo = ? AND f.name = ? "
! 1360: "ORDER BY d.path, f.name, p.name, h.hash",
! 1361: DB_INT, this->algo, DB_TEXT, this->file,
! 1362: DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1363: if (e)
! 1364: {
! 1365: while (e->enumerate(e, &id, &hash, &fid, &did, &dir, &pid, &product))
! 1366: {
! 1367: if (did != did_old)
! 1368: {
! 1369: printf("%6d: %s\n", did, dir);
! 1370: did_old = did;
! 1371: }
! 1372: if (fid != fid_old)
! 1373: {
! 1374: printf("%6d: %s\n", fid, this->file);
! 1375: fid_old = fid;
! 1376: pid_old = 0;
! 1377: }
! 1378: if (pid != pid_old)
! 1379: {
! 1380: printf("%6d: %s\n", pid, product);
! 1381: pid_old = pid;
! 1382: }
! 1383: printf("%6d: %s\n", id, hash);
! 1384: count++;
! 1385: }
! 1386: e->destroy(e);
! 1387:
! 1388: printf("%d %N value%s found\n", count, pts_meas_algorithm_names,
! 1389: this->algo, (count == 1) ? "" : "s");
! 1390: }
! 1391:
! 1392: }
! 1393: else if (this->did)
! 1394: {
! 1395: e = this->db->query(this->db,
! 1396: "SELECT h.id, h.hash, f.id, f.name, p.id, p.name "
! 1397: "FROM file_hashes AS h "
! 1398: "JOIN files AS f ON h.file = f.id "
! 1399: "JOIN versions AS v ON h.version = v.id "
! 1400: "JOIN products AS p ON v.product = p.id "
! 1401: "WHERE h.algo = ? AND f.dir = ? "
! 1402: "ORDER BY f.name, p.name, h.hash",
! 1403: DB_INT, this->algo, DB_INT, this->did,
! 1404: DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1405: if (e)
! 1406: {
! 1407: while (e->enumerate(e, &id, &hash, &fid, &file, &pid, &product))
! 1408: {
! 1409: if (fid != fid_old)
! 1410: {
! 1411: printf("%6d: %s\n", fid, file);
! 1412: fid_old = fid;
! 1413: pid_old = 0;
! 1414: }
! 1415: if (pid != pid_old)
! 1416: {
! 1417: printf("%6d: %s\n", pid, product);
! 1418: pid_old = pid;
! 1419: }
! 1420: printf("%6d: %s\n", id, hash);
! 1421: count++;
! 1422: }
! 1423: e->destroy(e);
! 1424:
! 1425: printf("%d %N value%s found for directory '%s'\n", count,
! 1426: pts_meas_algorithm_names, this->algo,
! 1427: (count == 1) ? "" : "s", this->dir);
! 1428: }
! 1429: }
! 1430: else
! 1431: {
! 1432: e = this->db->query(this->db,
! 1433: "SELECT h.id, h.hash, f.id, f.name, d.id, d.path, p.id, p.name "
! 1434: "FROM file_hashes AS h "
! 1435: "JOIN files AS f ON h.file = f.id "
! 1436: "JOIN directories AS d ON f.dir = d.id "
! 1437: "JOIN versions AS v ON h.version = v.id "
! 1438: "JOIN products AS p on v.product = p.id "
! 1439: "WHERE h.algo = ? "
! 1440: "ORDER BY d.path, f.name, p.name, h.hash",
! 1441: DB_INT, this->algo, DB_INT, DB_TEXT, DB_INT, DB_TEXT,
! 1442: DB_INT, DB_TEXT, DB_INT, DB_TEXT);
! 1443: if (e)
! 1444: {
! 1445: while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir, &pid,
! 1446: &product))
! 1447: {
! 1448: if (did != did_old)
! 1449: {
! 1450: printf("%6d: %s\n", did, dir);
! 1451: did_old = did;
! 1452: }
! 1453: if (fid != fid_old)
! 1454: {
! 1455: printf("%6d: %s\n", fid, file);
! 1456: fid_old = fid;
! 1457: pid_old = 0;
! 1458: }
! 1459: if (pid != pid_old)
! 1460: {
! 1461: printf("%6d: %s\n", pid, product);
! 1462: pid_old = pid;
! 1463: }
! 1464: printf("%6d: %s\n", id, hash);
! 1465: count++;
! 1466: }
! 1467: e->destroy(e);
! 1468:
! 1469: printf("%d %N value%s found\n", count, pts_meas_algorithm_names,
! 1470: this->algo, (count == 1) ? "" : "s");
! 1471: }
! 1472: }
! 1473: }
! 1474:
! 1475: METHOD(attest_db_t, list_measurements, void,
! 1476: private_attest_db_t *this)
! 1477: {
! 1478: enumerator_t *e;
! 1479: chunk_t hash, keyid;
! 1480: pts_comp_func_name_t *cfn;
! 1481: char *owner;
! 1482: int seq_no, pcr, vid, name, qualifier;
! 1483: int cid, cid_old = 0, kid, kid_old = 0, count = 0;
! 1484:
! 1485: if (this->kid && this->cid)
! 1486: {
! 1487: e = this->db->query(this->db,
! 1488: "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
! 1489: "FROM component_hashes AS ch "
! 1490: "JOIN keys AS k ON k.id = ch.key "
! 1491: "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
! 1492: "ORDER BY seq_no",
! 1493: DB_INT, this->algo, DB_UINT, this->kid, DB_UINT, this->cid,
! 1494: DB_INT, DB_INT, DB_BLOB, DB_TEXT);
! 1495: if (e)
! 1496: {
! 1497: while (e->enumerate(e, &seq_no, &pcr, &hash, &owner))
! 1498: {
! 1499: if (this->kid != kid_old)
! 1500: {
! 1501: printf("%4d: %#B '%s'\n", this->kid, &this->key, owner);
! 1502: kid_old = this->kid;
! 1503: }
! 1504: printf("%7d %02d %#B\n", seq_no, pcr, &hash);
! 1505: count++;
! 1506: }
! 1507: e->destroy(e);
! 1508:
! 1509: printf("%d %N value%s found for component '%s'\n", count,
! 1510: pts_meas_algorithm_names, this->algo,
! 1511: (count == 1) ? "" : "s", print_cfn(this->cfn));
! 1512: }
! 1513: }
! 1514: else if (this->cid)
! 1515: {
! 1516: e = this->db->query(this->db,
! 1517: "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
! 1518: "FROM component_hashes AS ch "
! 1519: "JOIN keys AS k ON k.id = ch.key "
! 1520: "WHERE ch.algo = ? AND ch.component = ? "
! 1521: "ORDER BY keyid, seq_no",
! 1522: DB_INT, this->algo, DB_UINT, this->cid,
! 1523: DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT);
! 1524: if (e)
! 1525: {
! 1526: while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner))
! 1527: {
! 1528: if (kid != kid_old)
! 1529: {
! 1530: printf("%4d: %#B '%s'\n", kid, &keyid, owner);
! 1531: kid_old = kid;
! 1532: }
! 1533: printf("%7d %02d %#B\n", seq_no, pcr, &hash);
! 1534: count++;
! 1535: }
! 1536: e->destroy(e);
! 1537:
! 1538: printf("%d %N value%s found for component '%s'\n", count,
! 1539: pts_meas_algorithm_names, this->algo,
! 1540: (count == 1) ? "" : "s", print_cfn(this->cfn));
! 1541: }
! 1542:
! 1543: }
! 1544: else if (this->kid)
! 1545: {
! 1546: e = this->db->query(this->db,
! 1547: "SELECT ch.seq_no, ch.pcr, ch.hash, "
! 1548: "c.id, c.vendor_id, c.name, c.qualifier "
! 1549: "FROM component_hashes AS ch "
! 1550: "JOIN components AS c ON c.id = ch.component "
! 1551: "WHERE ch.algo = ? AND ch.key = ? "
! 1552: "ORDER BY vendor_id, name, qualifier, seq_no",
! 1553: DB_INT, this->algo, DB_UINT, this->kid, DB_INT, DB_INT, DB_BLOB,
! 1554: DB_INT, DB_INT, DB_INT, DB_INT);
! 1555: if (e)
! 1556: {
! 1557: while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name,
! 1558: &qualifier))
! 1559: {
! 1560: if (cid != cid_old)
! 1561: {
! 1562: cfn = pts_comp_func_name_create(vid, name, qualifier);
! 1563: printf("%4d: %s\n", cid, print_cfn(cfn));
! 1564: cfn->destroy(cfn);
! 1565: cid_old = cid;
! 1566: }
! 1567: printf("%5d %02d %#B\n", seq_no, pcr, &hash);
! 1568: count++;
! 1569: }
! 1570: e->destroy(e);
! 1571:
! 1572: printf("%d %N value%s found for key %#B '%s'\n", count,
! 1573: pts_meas_algorithm_names, this->algo,
! 1574: (count == 1) ? "" : "s", &this->key, this->owner);
! 1575: }
! 1576: }
! 1577: }
! 1578:
! 1579: METHOD(attest_db_t, list_sessions, void,
! 1580: private_attest_db_t *this)
! 1581: {
! 1582: enumerator_t *e;
! 1583: chunk_t identity;
! 1584: char *product, *device;
! 1585: int session_id, conn_id, rec, device_len;
! 1586: time_t created;
! 1587: u_int t;
! 1588:
! 1589: e = this->db->query(this->db,
! 1590: "SELECT s.id, s.time, s.connection, s.rec, p.name, d.value, i.value "
! 1591: "FROM sessions AS s "
! 1592: "LEFT JOIN products AS p ON s.product = p.id "
! 1593: "LEFT JOIN devices AS d ON s.device = d.id "
! 1594: "LEFT JOIN identities AS i ON s.identity = i.id "
! 1595: "ORDER BY s.time DESC",
! 1596: DB_INT, DB_UINT, DB_INT, DB_INT, DB_TEXT, DB_TEXT, DB_BLOB);
! 1597: if (e)
! 1598: {
! 1599: while (e->enumerate(e, &session_id, &t, &conn_id, &rec, &product,
! 1600: &device, &identity))
! 1601: {
! 1602: created = t;
! 1603: product = product ? product : "-";
! 1604: device = strlen(device) ? device : "-";
! 1605: device_len = min(strlen(device), DEVICE_MAX_LEN);
! 1606: identity = identity.len ? identity : chunk_from_str("-");
! 1607: printf("%4d: %T %2d %-20s %.*s%*s%.*s - %N\n", session_id, &created,
! 1608: this->utc, conn_id, product, device_len, device,
! 1609: DEVICE_MAX_LEN - device_len + 1, " ", (int)identity.len,
! 1610: identity.ptr, TNC_IMV_Action_Recommendation_names, rec);
! 1611: }
! 1612: e->destroy(e);
! 1613: }
! 1614: }
! 1615:
! 1616: /**
! 1617: * Insert a file hash into the database
! 1618: */
! 1619: static bool insert_file_hash(private_attest_db_t *this,
! 1620: pts_meas_algorithms_t algo,
! 1621: chunk_t measurement, int fid,
! 1622: int *hashes_added, int *hashes_updated)
! 1623: {
! 1624: enumerator_t *e;
! 1625: uint8_t hex_measurement_buf[2*HASH_SIZE_SHA512 + 1];
! 1626: uint8_t *hex_hash_buf;
! 1627: chunk_t hex_hash, hex_measurement;
! 1628: char *label;
! 1629: bool insert = TRUE, update = FALSE;
! 1630:
! 1631: label = "could not be created";
! 1632:
! 1633: e = this->db->query(this->db,
! 1634: "SELECT hash FROM file_hashes "
! 1635: "WHERE algo = ? AND file = ? AND version = ?",
! 1636: DB_INT, algo, DB_UINT, fid, DB_UINT, this->vid, DB_TEXT);
! 1637:
! 1638: if (!e)
! 1639: {
! 1640: printf("file_hashes query failed\n");
! 1641: return FALSE;
! 1642: }
! 1643: hex_measurement = chunk_to_hex(measurement, hex_measurement_buf, FALSE);
! 1644:
! 1645: while (e->enumerate(e, &hex_hash_buf))
! 1646: {
! 1647: update = TRUE;
! 1648: hex_hash = chunk_from_str(hex_hash_buf);
! 1649:
! 1650: if (chunk_equals(hex_measurement, hex_hash))
! 1651: {
! 1652: label = "exists and equals";
! 1653: insert = FALSE;
! 1654: break;
! 1655: }
! 1656: }
! 1657: e->destroy(e);
! 1658:
! 1659: if (insert)
! 1660: {
! 1661: if (this->db->execute(this->db, NULL,
! 1662: "INSERT INTO file_hashes "
! 1663: "(file, version, algo, hash) "
! 1664: "VALUES (?, ?, ?, ?)",
! 1665: DB_UINT, fid, DB_UINT, this->vid,
! 1666: DB_INT, algo, DB_TEXT, hex_measurement) != 1)
! 1667: {
! 1668: printf("file_hash insertion failed\n");
! 1669: return FALSE;
! 1670: }
! 1671: if (update)
! 1672: {
! 1673: label = "updated";
! 1674: (*hashes_updated)++;
! 1675: }
! 1676: else
! 1677: {
! 1678: label = "created";
! 1679: (*hashes_added)++;
! 1680: }
! 1681: }
! 1682: printf(" %#B - %s\n", &measurement, label);
! 1683: return TRUE;
! 1684: }
! 1685:
! 1686: /**
! 1687: * Add a package version
! 1688: */
! 1689: static bool add_version(private_attest_db_t *this)
! 1690: {
! 1691: int vid, security_old, security, blacklist_old, blacklist;
! 1692: time_t t = time(NULL);
! 1693: enumerator_t *e;
! 1694: bool success;
! 1695:
! 1696: security = this->package_state == OS_PACKAGE_STATE_SECURITY;
! 1697: blacklist = this->package_state == OS_PACKAGE_STATE_BLACKLIST;
! 1698:
! 1699: e = this->db->query(this->db,
! 1700: "SELECT id, security, blacklist FROM versions "
! 1701: "WHERE package = ? AND product = ? AND release = ?",
! 1702: DB_UINT, this->gid, DB_UINT, this->pid, DB_TEXT, this->version,
! 1703: DB_INT, DB_INT, DB_INT, DB_INT);
! 1704: if (e)
! 1705: {
! 1706: if (e->enumerate(e, &vid, &security_old, &blacklist_old))
! 1707: {
! 1708: this->vid = vid;
! 1709: }
! 1710: e->destroy(e);
! 1711: }
! 1712: if (this->vid)
! 1713: {
! 1714: if (security != security_old || blacklist != blacklist_old)
! 1715: {
! 1716: /* update security and/or blacklist flag */
! 1717: success = this->db->execute(this->db, NULL, "UPDATE versions "
! 1718: "SET security = ?, blacklist = ?, time = ? WHERE id = ?",
! 1719: DB_INT, security, DB_INT, blacklist, DB_INT, t,
! 1720: DB_INT, this->vid) == 1;
! 1721:
! 1722: printf("'%s' package %s (%s)%N %s updated in database\n",
! 1723: this->product, this->package, this->version,
! 1724: os_package_state_names, this->package_state,
! 1725: success ? "" : "could not be ");
! 1726: }
! 1727: else
! 1728: {
! 1729: success = TRUE;
! 1730:
! 1731: printf("'%s' package %s (%s)%N exists in database\n",
! 1732: this->product, this->package, this->version,
! 1733: os_package_state_names, this->package_state);
! 1734: }
! 1735: return success;
! 1736: }
! 1737:
! 1738: /* create a new version */
! 1739: success = this->db->execute(this->db, NULL,
! 1740: "INSERT INTO versions "
! 1741: "(package, product, release, security, blacklist, time) "
! 1742: "VALUES (?, ?, ?, ?, ?, ?)",
! 1743: DB_UINT, this->gid, DB_INT, this->pid, DB_TEXT,
! 1744: this->version, DB_INT, security, DB_INT, blacklist,
! 1745: DB_INT, t) == 1;
! 1746:
! 1747: printf("'%s' package %s (%s)%N %sinserted into database\n",
! 1748: this->product, this->package, this->version,
! 1749: os_package_state_names, this->package_state,
! 1750: success ? "" : "could not be ");
! 1751:
! 1752: return success;
! 1753: }
! 1754:
! 1755: /**
! 1756: * Add hash measurement for a single file or all files in a directory
! 1757: */
! 1758: static bool add_hash(private_attest_db_t *this)
! 1759: {
! 1760: char *pathname, *filename, *label;
! 1761: const char *sep;
! 1762: pts_file_meas_t *measurements;
! 1763: chunk_t measurement;
! 1764: hasher_t *hasher = NULL;
! 1765: int fid, files_added = 0, hashes_added = 0, hashes_updated = 0;
! 1766: enumerator_t *enumerator, *e;
! 1767:
! 1768: if (!this->meas_dir)
! 1769: {
! 1770: this->meas_dir = strdup(this->dir);
! 1771: }
! 1772: sep = get_separator(this->meas_dir);
! 1773:
! 1774: if (this->fid)
! 1775: {
! 1776: /* build pathname from directory path and relative filename */
! 1777: if (asprintf(&pathname, "%s%s%s", this->meas_dir, sep, this->file) == -1)
! 1778: {
! 1779: return FALSE;
! 1780: }
! 1781: measurements = pts_file_meas_create_from_path(0, pathname, FALSE,
! 1782: TRUE, this->algo);
! 1783: free(pathname);
! 1784: }
! 1785: else
! 1786: {
! 1787: measurements = pts_file_meas_create_from_path(0, this->meas_dir, TRUE,
! 1788: TRUE, this->algo);
! 1789: }
! 1790: if (!measurements)
! 1791: {
! 1792: printf("file measurement failed\n");
! 1793: DESTROY_IF(hasher);
! 1794: return FALSE;
! 1795: }
! 1796:
! 1797: enumerator = measurements->create_enumerator(measurements);
! 1798: while (enumerator->enumerate(enumerator, &filename, &measurement))
! 1799: {
! 1800: if (this->fid)
! 1801: {
! 1802: /* a single file already exists */
! 1803: filename = this->file;
! 1804: fid = this->fid;
! 1805: label = "exists";
! 1806: }
! 1807: else
! 1808: {
! 1809: /* retrieve or create filename */
! 1810: label = "could not be created";
! 1811:
! 1812: e = this->db->query(this->db,
! 1813: "SELECT id FROM files WHERE name = ? AND dir = ?",
! 1814: DB_TEXT, filename, DB_INT, this->did, DB_INT);
! 1815: if (!e)
! 1816: {
! 1817: printf("files query failed\n");
! 1818: break;
! 1819: }
! 1820: if (e->enumerate(e, &fid))
! 1821: {
! 1822: label = "exists";
! 1823: }
! 1824: else
! 1825: {
! 1826: if (this->db->execute(this->db, &fid,
! 1827: "INSERT INTO files (name, dir) VALUES (?, ?)",
! 1828: DB_TEXT, filename, DB_INT, this->did) == 1)
! 1829: {
! 1830: label = "created";
! 1831: files_added++;
! 1832: }
! 1833: }
! 1834: e->destroy(e);
! 1835: }
! 1836: printf("%4d: %s - %s\n", fid, filename, label);
! 1837:
! 1838: /* compute file measurement hash */
! 1839: if (!insert_file_hash(this, this->algo, measurement, fid,
! 1840: &hashes_added, &hashes_updated))
! 1841: {
! 1842: break;
! 1843: }
! 1844: }
! 1845: enumerator->destroy(enumerator);
! 1846:
! 1847: printf("%d measurements, added %d new files, %d file hashes, "
! 1848: "updated %d file hashes\n",
! 1849: measurements->get_file_count(measurements),
! 1850: files_added, hashes_added, hashes_updated);
! 1851: measurements->destroy(measurements);
! 1852:
! 1853: return TRUE;
! 1854: }
! 1855:
! 1856: METHOD(attest_db_t, add, bool,
! 1857: private_attest_db_t *this)
! 1858: {
! 1859: /* insert package version */
! 1860: if (this->version_set && this->gid && this->pid)
! 1861: {
! 1862: if (!add_version(this))
! 1863: {
! 1864: return FALSE;
! 1865: }
! 1866: }
! 1867:
! 1868: /* add directory or file hash measurement for a given product */
! 1869: if (this->did && this->pid)
! 1870: {
! 1871: return add_hash(this);
! 1872: }
! 1873:
! 1874: return FALSE;
! 1875: }
! 1876:
! 1877: METHOD(attest_db_t, delete, bool,
! 1878: private_attest_db_t *this)
! 1879: {
! 1880: bool success;
! 1881: int id, count = 0;
! 1882: char *name;
! 1883: enumerator_t *e;
! 1884:
! 1885: /* delete a file measurement hash for a given product */
! 1886: if (this->algo && this->pid && this->fid)
! 1887: {
! 1888: success = this->db->execute(this->db, NULL,
! 1889: "DELETE FROM file_hashes AS h "
! 1890: "JOIN versions AS v ON h.version = v.id "
! 1891: "WHERE h.algo = ? AND v.product = ? AND h.file = ?",
! 1892: DB_UINT, this->algo, DB_UINT, this->pid,
! 1893: DB_UINT, this->fid) > 0;
! 1894:
! 1895: printf("%4d: %s%s%s\n", this->fid, this->dir, get_separator(this->dir),
! 1896: this->file);
! 1897: printf("%N value for product '%s' %sdeleted from database\n",
! 1898: pts_meas_algorithm_names, this->algo, this->product,
! 1899: success ? "" : "could not be ");
! 1900:
! 1901: return success;
! 1902: }
! 1903:
! 1904: /* delete product/file entries */
! 1905: if (this->pid && (this->fid || this->did))
! 1906: {
! 1907: success = this->db->execute(this->db, NULL,
! 1908: "DELETE FROM product_file "
! 1909: "WHERE product = ? AND file = ?",
! 1910: DB_UINT, this->pid,
! 1911: DB_UINT, this->fid ? this->fid : this->did) > 0;
! 1912:
! 1913: printf("product/file pair (%d/%d) %sdeleted from database\n",
! 1914: this->pid, this->fid ? this->fid : this->did,
! 1915: success ? "" : "could not be ");
! 1916:
! 1917: return success;
! 1918: }
! 1919:
! 1920: if (this->cid)
! 1921: {
! 1922: success = this->db->execute(this->db, NULL,
! 1923: "DELETE FROM components WHERE id = ?",
! 1924: DB_UINT, this->cid) > 0;
! 1925:
! 1926: printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
! 1927: success ? "" : "could not be ");
! 1928: return success;
! 1929: }
! 1930:
! 1931: if (this->fid)
! 1932: {
! 1933: success = this->db->execute(this->db, NULL,
! 1934: "DELETE FROM files WHERE id = ?",
! 1935: DB_UINT, this->fid) > 0;
! 1936:
! 1937: printf("file '%s%s%s' %sdeleted from database\n", this->dir,
! 1938: get_separator(this->dir), this->file,
! 1939: success ? "" : "could not be ");
! 1940: return success;
! 1941: }
! 1942:
! 1943: if (this->did)
! 1944: {
! 1945: e = this->db->query(this->db,
! 1946: "SELECT id, name FROM files WHERE dir = ? ORDER BY name",
! 1947: DB_INT, this->did, DB_INT, DB_TEXT);
! 1948: if (e)
! 1949: {
! 1950: while (e->enumerate(e, &id, &name))
! 1951: {
! 1952: printf("%4d: %s\n", id, name);
! 1953: count++;
! 1954: }
! 1955: e->destroy(e);
! 1956:
! 1957: if (count)
! 1958: {
! 1959: printf("%d dependent file%s found, "
! 1960: "directory '%s' could not deleted\n",
! 1961: count, (count == 1) ? "" : "s", this->dir);
! 1962: return FALSE;
! 1963: }
! 1964: }
! 1965: success = this->db->execute(this->db, NULL,
! 1966: "DELETE FROM directories WHERE id = ?",
! 1967: DB_UINT, this->did) > 0;
! 1968: printf("directory '%s' %sdeleted from database\n", this->dir,
! 1969: success ? "" : "could not be ");
! 1970: return success;
! 1971: }
! 1972:
! 1973: if (this->kid)
! 1974: {
! 1975: success = this->db->execute(this->db, NULL,
! 1976: "DELETE FROM keys WHERE id = ?",
! 1977: DB_UINT, this->kid) > 0;
! 1978:
! 1979: printf("key %#B %sdeleted from database\n", &this->key,
! 1980: success ? "" : "could not be ");
! 1981: return success;
! 1982: }
! 1983: if (this->pid)
! 1984: {
! 1985: success = this->db->execute(this->db, NULL,
! 1986: "DELETE FROM products WHERE id = ?",
! 1987: DB_UINT, this->pid) > 0;
! 1988:
! 1989: printf("product '%s' %sdeleted from database\n", this->product,
! 1990: success ? "" : "could not be ");
! 1991: return success;
! 1992: }
! 1993:
! 1994: printf("empty delete command\n");
! 1995: return FALSE;
! 1996: }
! 1997:
! 1998: METHOD(attest_db_t, destroy, void,
! 1999: private_attest_db_t *this)
! 2000: {
! 2001: DESTROY_IF(this->db);
! 2002: DESTROY_IF(this->cfn);
! 2003: free(this->package);
! 2004: free(this->product);
! 2005: free(this->version);
! 2006: free(this->file);
! 2007: free(this->dir);
! 2008: free(this->meas_dir);
! 2009: free(this->owner);
! 2010: free(this->key.ptr);
! 2011: free(this);
! 2012: }
! 2013:
! 2014: /**
! 2015: * Described in header.
! 2016: */
! 2017: attest_db_t *attest_db_create(char *uri)
! 2018: {
! 2019: private_attest_db_t *this;
! 2020:
! 2021: INIT(this,
! 2022: .public = {
! 2023: .set_component = _set_component,
! 2024: .set_cid = _set_cid,
! 2025: .set_directory = _set_directory,
! 2026: .set_did = _set_did,
! 2027: .set_file = _set_file,
! 2028: .set_fid = _set_fid,
! 2029: .set_meas_directory = _set_meas_directory,
! 2030: .set_key = _set_key,
! 2031: .set_kid = _set_kid,
! 2032: .set_package = _set_package,
! 2033: .set_gid = _set_gid,
! 2034: .set_product = _set_product,
! 2035: .set_pid = _set_pid,
! 2036: .set_version = _set_version,
! 2037: .set_algo = _set_algo,
! 2038: .set_relative = _set_relative,
! 2039: .set_package_state = _set_package_state,
! 2040: .set_sequence = _set_sequence,
! 2041: .set_owner = _set_owner,
! 2042: .set_utc = _set_utc,
! 2043: .list_packages = _list_packages,
! 2044: .list_products = _list_products,
! 2045: .list_files = _list_files,
! 2046: .list_directories = _list_directories,
! 2047: .list_components = _list_components,
! 2048: .list_devices = _list_devices,
! 2049: .list_keys = _list_keys,
! 2050: .list_hashes = _list_hashes,
! 2051: .list_measurements = _list_measurements,
! 2052: .list_sessions = _list_sessions,
! 2053: .add = _add,
! 2054: .delete = _delete,
! 2055: .destroy = _destroy,
! 2056: },
! 2057: .db = lib->db->create(lib->db, uri),
! 2058: );
! 2059:
! 2060: if (!this->db)
! 2061: {
! 2062: fprintf(stderr, "opening database failed.\n");
! 2063: destroy(this);
! 2064: return NULL;
! 2065: }
! 2066:
! 2067: return &this->public;
! 2068: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>