static void test_isotime2epoch (void) { struct { const char *string; time_t expected; } array [] = { { "19700101T000001", 1 }, { "19700101T235959", 86399 }, { "19980815T143712", 903191832 }, { "19700101T000000", 0 }, { "19691231T235959", INVALID }, { "19000101T000000", INVALID }, { "", INVALID }, { "19000101T00000", INVALID }, { "20010101t123456", INVALID }, { "20010101T123456", 978352496 }, { "20070629T160000", 1183132800 }, { "20070629T160000:", 1183132800 }, { "20070629T160000,", 1183132800 }, { "20070629T160000 ", 1183132800 }, { "20070629T160000\n", 1183132800 }, { "20070629T160000.", INVALID }, { NULL, 0 } }; int idx; time_t val; gnupg_isotime_t tbuf; for (idx=0; array[idx].string; idx++) { val = isotime2epoch (array[idx].string); if (val != array[idx].expected ) { fail (idx); if (verbose) fprintf (stderr, "string `%s' exp: %ld got: %ld\n", array[idx].string, (long)array[idx].expected, (long)val); } if (array[idx].expected != INVALID) { epoch2isotime (tbuf, val); if (strlen (tbuf) != 15) { if (verbose) fprintf (stderr, "string `%s', time-t %ld, revert: `%s'\n", array[idx].string, (long)val, tbuf); fail (idx); } if (strncmp (array[idx].string, tbuf, 15)) fail (idx); } } }
int main ( int argc, char **argv) { ARGPARSE_ARGS pargs; int orig_argc; char **orig_argv; gpg_error_t err = 0; /* const char *fname; */ int may_coredump; FILE *configfp = NULL; char *configname = NULL; unsigned configlineno; int parse_debug = 0; int no_more_options = 0; int default_config =1; char *logfile = NULL; /* int debug_wait = 0; */ int use_random_seed = 1; /* int nodetach = 0; */ /* int nokeysetup = 0; */ struct server_control_s ctrl; /*mtrace();*/ early_system_init (); gnupg_reopen_std (G13_NAME "-syshelp"); set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); log_set_prefix (G13_NAME "-syshelp", 1); /* Make sure that our subsystems are ready. */ i18n_init (); init_common_subsystems (&argc, &argv); /* Check that the Libgcrypt is suitable. */ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt", NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); /* Take extra care of the random pool. */ gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); may_coredump = disable_core_dumps (); g13_init_signals (); dotlock_create (NULL, 0); /* Register locking cleanup. */ opt.session_env = session_env_new (); if (!opt.session_env) log_fatal ("error allocating session environment block: %s\n", strerror (errno)); opt.homedir = default_homedir (); /* Fixme: We enable verbose mode here because there is currently no way to do this when starting g13-syshelp. To fix that we should add a g13-syshelp.conf file in /etc/gnupg. */ opt.verbose = 1; /* First check whether we have a debug option on the commandline. */ orig_argc = argc; orig_argv = argv; pargs.argc = &argc; pargs.argv = &argv; pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION); while (arg_parse( &pargs, opts)) { if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll) parse_debug++; } /* Initialize the secure memory. */ gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); maybe_setuid = 0; /* Now we are now working under our real uid */ /* Setup malloc hooks. */ { struct assuan_malloc_hooks malloc_hooks; malloc_hooks.malloc = gcry_malloc; malloc_hooks.realloc = gcry_realloc; malloc_hooks.free = gcry_free; assuan_set_malloc_hooks (&malloc_hooks); } /* Prepare libassuan. */ assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/ setup_libassuan_logging (&opt.debug); /* Setup a default control structure for command line mode. */ memset (&ctrl, 0, sizeof ctrl); g13_syshelp_init_default_ctrl (&ctrl); ctrl.no_server = 1; ctrl.status_fd = -1; /* No status output. */ if (default_config ) configname = make_filename (gnupg_sysconfdir (), G13_NAME"-syshelp.conf", NULL); argc = orig_argc; argv = orig_argv; pargs.argc = &argc; pargs.argv = &argv; pargs.flags = 1; /* Do not remove the args. */ next_pass: if (configname) { configlineno = 0; configfp = fopen (configname, "r"); if (!configfp) { if (default_config) { if (parse_debug) log_info (_("NOTE: no default option file '%s'\n"), configname); } else { log_error (_("option file '%s': %s\n"), configname, strerror(errno)); g13_exit(2); } xfree (configname); configname = NULL; } if (parse_debug && configname) log_info (_("reading options from '%s'\n"), configname); default_config = 0; } while (!no_more_options && optfile_parse (configfp, configname, &configlineno, &pargs, opts)) { switch (pargs.r_opt) { case oQuiet: opt.quiet = 1; break; case oDryRun: opt.dry_run = 1; break; case oVerbose: opt.verbose++; gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); break; case oNoVerbose: opt.verbose = 0; gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); break; case oLogFile: logfile = pargs.r.ret_str; break; case oNoLogFile: logfile = NULL; break; case oNoDetach: /*nodetach = 1; */break; case oDebug: if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags)) { pargs.r_opt = ARGPARSE_INVALID_ARG; pargs.err = ARGPARSE_PRINT_ERROR; } break; case oDebugAll: debug_value = ~0; break; case oDebugNone: debug_value = 0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugWait: /*debug_wait = pargs.r.ret_int; */break; case oDebugAllowCoreDump: may_coredump = enable_core_dumps (); break; case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break; case oLoggerFD: log_set_fd (pargs.r.ret_int ); break; case oHomedir: opt.homedir = pargs.r.ret_str; break; case oFakedSystemTime: { time_t faked_time = isotime2epoch (pargs.r.ret_str); if (faked_time == (time_t)(-1)) faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10); gnupg_set_time (faked_time, 0); } break; case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break; case oNoRandomSeedFile: use_random_seed = 0; break; default: pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR; break; } } if (configfp) { fclose (configfp); configfp = NULL; /* Keep a copy of the config filename. */ opt.config_filename = configname; configname = NULL; goto next_pass; } xfree (configname); configname = NULL; if (!opt.config_filename) opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL); if (log_get_errorcount(0)) g13_exit(2); /* Now that we have the options parsed we need to update the default control structure. */ g13_syshelp_init_default_ctrl (&ctrl); if (may_coredump && !opt.quiet) log_info (_("WARNING: program may create a core file!\n")); if (logfile) { log_set_file (logfile); log_set_prefix (NULL, 1|2|4); } if (gnupg_faked_time_p ()) { gnupg_isotime_t tbuf; log_info (_("WARNING: running with faked system time: ")); gnupg_get_isotime (tbuf); dump_isotime (tbuf); log_printf ("\n"); } /* Print any pending secure memory warnings. */ gcry_control (GCRYCTL_RESUME_SECMEM_WARN); /* Setup the debug flags for all subsystems. */ set_debug (); /* Install a regular exit handler to make real sure that the secure memory gets wiped out. */ g13_install_emergency_cleanup (); /* Terminate if we found any error until now. */ if (log_get_errorcount(0)) g13_exit (2); /* Set the standard GnuPG random seed file. */ if (use_random_seed) { char *p = make_filename (opt.homedir, "random_seed", NULL); gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p); xfree(p); } /* Get the UID of the caller. */ #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) { const char *uidstr; struct passwd *pwd = NULL; uidstr = getenv ("USERV_UID"); /* Print a quick note if we are not started via userv. */ if (!uidstr) { if (getuid ()) { log_info ("WARNING: Not started via userv\n"); ctrl.fail_all_cmds = 1; } ctrl.client.uid = getuid (); } else { unsigned long myuid; errno = 0; myuid = strtoul (uidstr, NULL, 10); if (myuid == ULONG_MAX && errno) { log_info ("WARNING: Started via broken userv: %s\n", strerror (errno)); ctrl.fail_all_cmds = 1; ctrl.client.uid = getuid (); } else ctrl.client.uid = (uid_t)myuid; } pwd = getpwuid (ctrl.client.uid); if (!pwd || !*pwd->pw_name) { log_info ("WARNING: Name for UID not found: %s\n", strerror (errno)); ctrl.fail_all_cmds = 1; ctrl.client.uname = xstrdup ("?"); } else ctrl.client.uname = xstrdup (pwd->pw_name); /* Check that the user name does not contain a directory separator. */ if (strchr (ctrl.client.uname, '/')) { log_info ("WARNING: Invalid user name passed\n"); ctrl.fail_all_cmds = 1; } } #else /*!HAVE_PWD_H || !HAVE_GETPWUID*/ log_info ("WARNING: System does not support required syscalls\n"); ctrl.fail_all_cmds = 1; ctrl.client.uid = getuid (); ctrl.client.uname = xstrdup ("?"); #endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/ /* Read the table entries for this user. */ if (!ctrl.fail_all_cmds && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname))) ctrl.fail_all_cmds = 1; /* Start the server. */ err = syshelp_server (&ctrl); if (err) log_error ("server exited with error: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); /* Cleanup. */ g13_syshelp_deinit_default_ctrl (&ctrl); g13_exit (0); return 8; /*NOTREACHED*/ }
gpg_error_t cmd_genkey (assuan_context_t ctx, char *line) { gpg_err_code_t error = GPG_ERR_GENERAL; pkcs11h_certificate_id_t cert_id = NULL; gcry_mpi_t n_mpi = NULL; gcry_mpi_t e_mpi = NULL; unsigned char *n_hex = NULL; unsigned char *e_hex = NULL; char *n_resp = strdup ("n "); char *e_resp = strdup ("e "); unsigned char *blob = NULL; char *serial = NULL; char *key = NULL; size_t blob_size; char timestamp[100] = {0}; while (*line != '\x0' && !isdigit (*line)) { if (*line == '-') { static const char *ts = "--timestamp="; char *p = line; while (*line != '\x0' && !isspace (*line)) { line++; } line++; if (!strncmp (p, ts, strlen (ts))) { p += strlen (ts); sprintf (timestamp, "%d", (int)isotime2epoch (p)); } } else { line++; } } if (*line == '\x0') { error = GPG_ERR_INV_DATA; goto cleanup; } if (strlen (timestamp) == 0) { sprintf (timestamp, "%d", (int)time (NULL)); } if ( (error = _get_certificate_by_name ( ctx, NULL, atoi(line), &cert_id, &key )) != GPG_ERR_NO_ERROR ) { goto cleanup; } if ( (error = assuan_write_status ( ctx, "KEY-FPR", key )) != GPG_ERR_NO_ERROR || (error = assuan_write_status( ctx, "KEY-CREATED-AT", timestamp )) != GPG_ERR_NO_ERROR ) { goto cleanup; } if ((error = get_serial_of_tokenid(cert_id->token_id, &serial)) != GPG_ERR_NO_ERROR) { goto cleanup; } if ( (error = assuan_write_status ( ctx, "SERIALNO", serial )) != GPG_ERR_NO_ERROR || (error = get_cert_blob ( ctx, cert_id, &blob, &blob_size )) != GPG_ERR_NO_ERROR || (error = keyutil_get_cert_mpi ( blob, blob_size, &n_mpi, &e_mpi )) != GPG_ERR_NO_ERROR ) { goto cleanup; } if ( gcry_mpi_aprint ( GCRYMPI_FMT_HEX, &n_hex, NULL, n_mpi ) || gcry_mpi_aprint ( GCRYMPI_FMT_HEX, &e_hex, NULL, e_mpi ) ) { error = GPG_ERR_BAD_KEY; goto cleanup; } if ( !encoding_strappend (&n_resp, (char *)n_hex) || !encoding_strappend (&e_resp, (char *)e_hex) ) { error = GPG_ERR_ENOMEM; goto cleanup; } if ( (error = assuan_write_status( ctx, "KEY-DATA", n_resp )) != GPG_ERR_NO_ERROR ) { goto cleanup; } if ( (error = assuan_write_status( ctx, "KEY-DATA", e_resp )) != GPG_ERR_NO_ERROR ) { goto cleanup; } error = GPG_ERR_NO_ERROR; cleanup: if (n_mpi != NULL) { gcry_mpi_release (n_mpi); n_mpi = NULL; } if (e_mpi != NULL) { gcry_mpi_release (e_mpi); e_mpi = NULL; } if (n_hex != NULL) { gcry_free (n_hex); n_hex = NULL; } if (e_hex != NULL) { gcry_free (e_hex); e_hex = NULL; } if (n_resp != NULL) { free (n_resp); n_resp = NULL; } if (e_resp != NULL) { free (e_resp); e_resp = NULL; } if (blob != NULL) { free (blob); blob = NULL; } if (cert_id != NULL) { pkcs11h_certificate_freeCertificateId (cert_id); cert_id = NULL; } if (serial != NULL) { free(serial); serial = NULL; } return gpg_error (error); }