/* * sets up and performs the database query, and handles the results */ static err_code doQuery( char **displays, char **filters, char *orderp) { scmtab *table = NULL; scmsrcha srch; scmsrch srch1[MAX_VALS]; char whereStr[MAX_CONDS * 20]; char errMsg[1024]; int srchFlags = SCM_SRCH_DOVALUE_ALWAYS; unsigned long blah = 0; int i; int j; err_code status; QueryField *field; QueryField *field2; char *name; int maxW = MAX_CONDS * 20; (void)setbuf(stdout, NULL); scmp = initscm(); checkErr(scmp == NULL, "Cannot initialize database schema\n"); connection = connectscm(scmp->dsn, errMsg, 1024); checkErr(connection == NULL, "Cannot connect to database: %s\n", errMsg); connection->mystat.tabname = objectType; table = findtablescm(scmp, tableName(objectType)); checkErr(table == NULL, "Cannot find table %s\n", objectType); /* * set up where clause, i.e. the filter */ srch.where = NULL; whereStr[0] = 0; if (filters == NULL || filters[0] == NULL) { srch.wherestr = NULL; } else { whereStr[0] = (char)0; for (i = 0; filters[i] != NULL; i++) { if (i != 0) strncat(whereStr, " AND ", maxW - strlen(whereStr)); name = strtok(filters[i], "."); strncat(whereStr, name, maxW - strlen(whereStr)); field = findField(name); checkErr(field == NULL || field->description == NULL, "Unknown field name: %s\n", name); checkErr(field->flags & Q_JUST_DISPLAY, "Field only for display: %s\n", name); name = strtok(NULL, "."); if (!name) checkErr(1, "No comparison operator\n"); if (strcasecmp(name, "eq") == 0) { strncat(whereStr, "=", maxW - strlen(whereStr)); } else if (strcasecmp(name, "ne") == 0) { strncat(whereStr, "<>", maxW - strlen(whereStr)); } else if (strcasecmp(name, "lt") == 0) { strncat(whereStr, "<", maxW - strlen(whereStr)); } else if (strcasecmp(name, "gt") == 0) { strncat(whereStr, ">", maxW - strlen(whereStr)); } else if (strcasecmp(name, "le") == 0) { strncat(whereStr, "<=", maxW - strlen(whereStr)); } else if (strcasecmp(name, "ge") == 0) { strncat(whereStr, ">=", maxW - strlen(whereStr)); } else { checkErr(1, "Bad comparison operator: %s\n", name); } strncat(whereStr, "\"", maxW - strlen(whereStr)); name = strtok(NULL, ""); for (j = 0; j < (int)strlen(name); j++) { if (name[j] == '#') name[j] = ' '; } char escaped [strlen(name)*2+1]; mysql_escape_string(escaped, name, strlen(name)); strncat(whereStr, escaped, maxW - strlen(whereStr)); strncat(whereStr, "\"", maxW - strlen(whereStr)); } srch.wherestr = whereStr; } if (validate) { addQueryFlagTests(whereStr, srch.wherestr != NULL); srch.wherestr = whereStr; } /* * set up columns to select */ srch.vec = srch1; srch.sname = NULL; srch.ntot = MAX_VALS; srch.nused = 0; srch.vald = 0; srch.context = &blah; for (i = 0; displays[i] != NULL; i++) { field = findField(displays[i]); checkErr(field == NULL || field->description == NULL, "Unknown field name: %s\n", displays[i]); globalFields[i] = field; name = (field->dbColumn == NULL) ? displays[i] : field->dbColumn; while (name != NULL) { field2 = findField(name); /** @bug ignores error code without explanation */ addcolsrchscm(&srch, name, field2->sqlType, field2->maxSize); if (field->flags & Q_REQ_JOIN) srchFlags = srchFlags | SCM_SRCH_DO_JOIN; name = (name == field->otherDBColumn) ? NULL : field->otherDBColumn; } } globalFields[i] = NULL; if (validate) { valIndex = srch.nused; if (isROA || isManifest || isCRL || isGBR) { char *ski; if (isCRL) { ski = "aki"; } else { ski = "ski"; } field2 = findField(ski); /** @bug ignores error code without explanation */ addcolsrchscm(&srch, ski, field2->sqlType, field2->maxSize); } else if (isCert) /** @bug ignores error code without explanation */ addcolsrchscm(&srch, "local_id", SQL_C_ULONG, 8); } /* * do query */ status = searchscm(connection, table, &srch, NULL, &handleResults, srchFlags, orderp); for (i = 0; i < srch.nused; i++) { free(srch.vec[i].colname); free(srch1[i].valptr); } return status; }
int main( int argc, char **argv) { scmcon *testconp = NULL; scmcon *realconp = NULL; scm *scmp = NULL; FILE *sfile = NULL; char *thedelfile = NULL; char *topdir = NULL; char *thefile = NULL; char *outfile = NULL; char *outfull = NULL; char *outdir = NULL; char *tmpdsn = NULL; char *ne; char *porto = NULL; char errmsg[1024]; char *skifile = NULL; int ians = 0; int do_create = 0; int do_delete = 0; int do_sockopts = 0; int do_fileopts = 0; int use_filelist = 0; int perpetual = 0; int really = 0; int trusted = 0; int force = 0; int allowex = 0; int sta = 0; int s; int c; (void)setbuf(stdout, NULL); if (argc <= 1) { usage(); return (1); } while ((c = getopt(argc, argv, "t:xyhad:f:F:lLwz:pm:c:s")) != EOF) { switch (c) { case 'a': allowex = 1; break; case 't': do_create++; topdir = optarg; break; case 'x': do_delete++; break; case 'y': force++; break; case 'D': trusted++; case 'd': thedelfile = optarg; break; case 'F': trusted++; case 'f': thefile = optarg; break; case 'L': trusted++; case 'l': use_filelist++; break; case 'w': do_sockopts++; break; case 'z': do_fileopts++; porto = optarg; break; case 'p': perpetual++; break; case 'c': skifile = optarg; break; case 'h': usage(); return (0); case 's': strict_profile_checks = 1; // global from myssl.c strict_profile_checks_cms = 1; // global from roa_validate.c break; default: (void)fprintf(stderr, "Invalid option '%c'\n", c); usage(); return (1); } } // if there is anything left in argv, or no operation specified, warn user if (optind < argc) { (void)printf("Extra arguments at the end of the command line.\n"); usage(); return (1); } if ((do_create + do_delete + do_sockopts + do_fileopts) == 0 && thefile == 0 && thedelfile == 0 && skifile == 0 && use_filelist == 0) { (void)printf("You need to specify at least one operation " "(e.g. -f file).\n"); usage(); return (1); } OPEN_LOG("rcli", LOG_USER); if (!my_config_load()) { LOG(LOG_ERR, "can't load configuration"); exit(EXIT_FAILURE); } if (force == 0) { if (do_delete > 0) { ians = yorn("Do you REALLY want to delete all database tables"); if (ians <= 0) { LOG(LOG_NOTICE, "Delete operation cancelled"); return (1); } really++; } if ((do_create > 0) && (really == 0)) { ians = yorn("Do you REALLY want to create all database tables"); if (ians <= 0) { LOG(LOG_NOTICE, "Create operation cancelled"); return (1); } really++; } } scmp = initscm(); if (scmp == NULL) { LOG(LOG_ERR, "Internal error: cannot initialize database schema"); return (-2); } /* * If a create or delete operation is being performed, then a test dsn * will be needed; create it now and defer the creation of the real dsn * until later. Otherwise, create the real dsn. * * A test dsn is needed for operations that operate on the overall * database state as opposed to the rpki tables, namely the create and * delete operations. */ if ((do_create + do_delete) > 0) { /* * Note that in the following line, we do not intend to edit * the database named "information_schema". We are simply * filling in the "database name" parameter with something * that is guaranteed to be valid for MySQL. */ tmpdsn = makedsnscm(scmp->dsnpref, "information_schema", CONFIG_DATABASE_USER_get(), CONFIG_DATABASE_PASSWORD_get()); if (tmpdsn == NULL) { membail(); return (-1); } testconp = connectscm(tmpdsn, errmsg, 1024); memset(tmpdsn, 0, strlen(tmpdsn)); free((void *)tmpdsn); if (testconp == NULL) { LOG(LOG_ERR, "Cannot connect to DSN: %s", errmsg); freescm(scmp); return (-1); } } else { realconp = connectscm(scmp->dsn, errmsg, 1024); if (realconp == NULL) { LOG(LOG_ERR, "Cannot connect to DSN %s: %s", scmp->dsn, errmsg); freescm(scmp); return (-1); } } /* * Process command line options in the following order: delete, create, * dofile, dodir, listener. */ if (do_delete > 0) sta = deleteop(testconp, scmp); if ((do_create > 0) && (sta == 0)) /* first phase of create */ sta = createop(testconp, scmp); /* * Don't need the test connection any more */ if (testconp != NULL) { disconnectscm(testconp); testconp = NULL; } /* * If there has been an error or if we're done because the database was * just deleted and not re-created, bail out. */ if (sta < 0 || (do_delete > 0 && do_create == 0)) { if (realconp != NULL) disconnectscm(realconp); freescm(scmp); if (tdir != NULL) free((void *)tdir); return (sta); } /* * If a connection to the real DSN has not been opened yet, open it now. */ if (realconp == NULL) { realconp = connectscm(scmp->dsn, errmsg, 1024); if (realconp == NULL) { LOG(LOG_ERR, "Cannot connect to DSN %s: %s", scmp->dsn, errmsg); freescm(scmp); if (tdir != NULL) free((void *)tdir); return (-1); } } /* * If a create operation was requested, complete it now. */ if ((do_create > 0) && (sta == 0)) sta = create2op(scmp, realconp, topdir); /* * If the top level repository directory is not set, then retrieve it from * the database. */ if ((tdir == NULL) && (sta == 0)) { tdir = retrieve_tdir(scmp, realconp, &sta); if (tdir == NULL) LOG(LOG_ERR, "Cannot retrieve top level repository info from DB"); } if (sta == 0) { LOG(LOG_INFO, "Top level repository directory is %s", tdir); tdirlen = strlen(tdir); } /* * Setup for actual SSL operations */ OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); LOG(LOG_NOTICE, "Rsync client session started"); if (thefile != NULL && sta == 0) { // Check that the file is in the repository, ask if not and force is // off sta = splitdf(NULL, NULL, thefile, &outdir, &outfile, &outfull); if (sta == 0) { if (strncmp(tdir, outdir, tdirlen) != 0 && force == 0) { ians = yorn("That file is not in the repository. Proceed anyway"); if (ians <= 0) sta = 1; } // if ( strstr(outdir, "TRUST") != NULL ) // trusted++; // if the user has declared it to be trusted // ask for verification unless force is set if (trusted > 0 && force == 0 && sta == 0) { ians = yorn("Really declare this file as trusted"); if (ians <= 0) sta = 1; } if (sta == 1) LOG(LOG_NOTICE, "File operation cancelled"); if (sta == 0) { LOG(LOG_INFO, "Attempting add: %s", outfile); setallowexpired(allowex); sta = add_object(scmp, realconp, outfile, outdir, outfull, trusted); if (sta < 0) { LOG(LOG_ERR, "Add failed: %s: error %s (%d)", thefile, err2string(sta), sta); if (sta == ERR_SCM_SQL) { ne = geterrorscm(realconp); if (ne != NULL && ne != 0) LOG(LOG_ERR, "\t%s", ne); } } else LOG(LOG_INFO, "Add succeeded: %s", outfile); } free((void *)outdir); free((void *)outfile); free((void *)outfull); } else LOG(LOG_ERR, "%s (%d)", err2string(sta), sta); } if (use_filelist > 0 && sta == 0) { char *line = NULL; size_t len = 0; ssize_t read; int status; setallowexpired(allowex); while ((read = getline(&line, &len, stdin)) != -1) { if (read == 0) continue; // Trim newline and skip line if empty if (line[read - 1] == '\n') line[read - 1] = '\0'; if (strlen(line) == 0) continue; // Split directory and file components of path status = splitdf(NULL, NULL, line, &outdir, &outfile, &outfull); if (status != 0) { LOG(LOG_ERR, "%s (%d)", err2string(status), status); continue; } LOG(LOG_INFO, "Attempting add: %s", outfile); // Warn if file not within repository directory if (strncmp(tdir, outdir, tdirlen) != 0) LOG(LOG_WARNING, "%s is not in the repository", line); // Add status = add_object(scmp, realconp, outfile, outdir, outfull, trusted); if (status == 0) { LOG(LOG_INFO, "Add succeeded: %s", outfile); } else { LOG(LOG_ERR, "Add failed: %s: error %s (%d)", line, err2string(status), status); if (status == ERR_SCM_SQL) { ne = geterrorscm(realconp); if (ne != NULL && ne != 0) LOG(LOG_ERR, "\t%s", ne); } } free((void *)outdir); free((void *)outfile); free((void *)outfull); } free(line); } if (thedelfile != NULL && sta == 0) { sta = splitdf(NULL, NULL, thedelfile, &outdir, &outfile, &outfull); if (sta == 0) { sta = delete_object(scmp, realconp, outfile, outdir, outfull, 0); if (sta < 0) { LOG(LOG_ERR, "Could not delete file %s: error %s (%d)", thedelfile, err2string(sta), sta); if (sta == ERR_SCM_SQL) { ne = geterrorscm(realconp); if (ne != NULL && ne != 0) LOG(LOG_ERR, "\t%s", ne); } } else LOG(LOG_INFO, "Delete operation succeeded (%s removed)", thedelfile); free((void *)outdir); free((void *)outfile); free((void *)outfull); } else LOG(LOG_ERR, "Error: %s (%d)", err2string(sta), sta); } if ((do_sockopts + do_fileopts) > 0 && sta == 0) { int protos = (-1); const int max_makesock_attempts = 10; int makesock_failures = 0; do { if (do_sockopts > 0) { uint16_t port = CONFIG_RPKI_PORT_get(); s = makesock(port, &protos); if (s < 0) { makesock_failures++; LOG(LOG_ERR, "Failed to listen on port %" PRIu16 " (failure #%d)", port, makesock_failures); sleep(1); if (makesock_failures >= max_makesock_attempts) { LOG(LOG_ERR, "%d failed attempts to create socket. Aborting.", max_makesock_attempts); sta = -1; break; } } else { makesock_failures = 0; FLUSH_LOG(); sta = sockline(scmp, realconp, s); LOG(LOG_INFO, "Socket connection closed"); FLUSH_LOG(); (void)close(s); } } if (do_fileopts > 0 && porto != NULL) { if (!isatty(0)) { LOG(LOG_DEBUG, "Opening stdin"); sfile = stdin; sta = fileline(scmp, realconp, sfile); } else { LOG(LOG_DEBUG, "Opening a socket cmdfile %s", porto); sfile = fopen(porto, "r"); if (sfile == NULL) LOG(LOG_ERR, "Could not open cmdfile"); else { sta = fileline(scmp, realconp, sfile); LOG(LOG_DEBUG, "Cmdfile closed"); (void)fclose(sfile); } } } if (sta == 0 && skifile) { LOG(LOG_DEBUG, "Starting skifile %s", skifile); sta = read_SKI_blocks(scmp, realconp, skifile); if (sta > 0) sta = 0; if (sta) LOG(LOG_ERR, "Error with skifile: %s (%d)", err2string(sta), sta); } } while (perpetual > 0); if (protos >= 0) (void)close(protos); } if (sta == 0 && skifile) { LOG(LOG_DEBUG, "Starting skifile %s", skifile); sta = read_SKI_blocks(scmp, realconp, skifile); if (sta > 0) sta = 0; if (sta) LOG(LOG_ERR, "Error with skifile: %s (%d)", err2string(sta), sta); } (void)ranlast(scmp, realconp, "RSYNC"); sqcleanup(); if (realconp != NULL) disconnectscm(realconp); freescm(scmp); if (tdir != NULL) free((void *)tdir); LOG(LOG_NOTICE, "Rsync client session ended"); config_unload(); CLOSE_LOG(); return (sta); }