diff -u gnupg-1.0.3/g10/Makefile.in gnupg-api/g10/Makefile.in --- gnupg-1.0.3/g10/Makefile.in Sat Nov 4 10:45:59 2000 +++ gnupg-api/g10/Makefile.in Mon Oct 23 16:28:07 2000 @@ -138,7 +138,7 @@ DEFS = @DEFS@ -I. -I$(srcdir) -I.. CPPFLAGS = @CPPFLAGS@ LIBS = @LIBS@ -gpg_OBJECTS = g10.o build-packet.o compress.o free-packet.o getkey.o \ +gpg_OBJECTS = build-packet.o compress.o free-packet.o getkey.o \ delkey.o pkclist.o skclist.o ringedit.o kbnode.o mainproc.o armor.o \ mdfilter.o textfilter.o cipher.o misc.o openfile.o keyid.o trustdb.o \ tdbdump.o tdbio.o hkp.o parse-packet.o passphrase.o pubkey-enc.o \ @@ -149,7 +149,7 @@ gpg_DEPENDENCIES = ../cipher/libcipher.a ../mpi/libmpi.a \ ../util/libutil.a gpg_LDFLAGS = -CFLAGS = @CFLAGS@ +CFLAGS = @CFLAGS@ -ggdb COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ @@ -218,9 +218,10 @@ maintainer-clean-compile: -gpg: $(gpg_OBJECTS) $(gpg_DEPENDENCIES) +gpg: $(gpg_OBJECTS) g10.o $(gpg_DEPENDENCIES) main.c @rm -f gpg - $(LINK) $(gpg_LDFLAGS) $(gpg_OBJECTS) $(gpg_LDADD) $(LIBS) + gcc -c main.c -o main.o + $(LINK) $(gpg_LDFLAGS) main.o $(gpg_OBJECTS) g10.o $(gpg_LDADD) $(LIBS) tags: TAGS @@ -592,3 +593,8 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Dodgy stuff added by Mikal to get the API up and running +api: gpg api.c + ar rs libgpg.a `ls *.o | grep -v main.o` ../cipher/*.o ../mpi/*.o ../util/*.o + gcc -ggdb api.c -L. -lgpg -o api -lz -ldl -lgdbm diff -u gnupg-1.0.3/g10/g10.c gnupg-api/g10/g10.c --- gnupg-1.0.3/g10/g10.c Sat Nov 4 10:45:59 2000 +++ gnupg-api/g10/g10.c Fri Oct 20 13:19:54 2000 @@ -47,7 +47,9 @@ #include "g10defs.h" #include "hkp.h" - +/** A list of all the command line options supported and their possible single + letter shortcuts. This is used to build the information for the ARG_PARSE + command line parser. See the next block after this one... */ enum cmd_and_opt_values { aNull = 0, oArmor = 'a', aDetachedSign = 'b', @@ -200,7 +202,8 @@ oEmuMDEncodeBug, aTest }; - +/** This is used by the ARG_PARSE stuff in the main() function to parse + arguements passed to GPG on the command line interface */ static ARGPARSE_OPTS opts[] = { { 300, NULL, 0, N_("@Commands:\n ") }, @@ -388,7 +391,10 @@ { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"}, {0} }; +/** End of the stuff relating to ARG_PARSE */ +/** The presence of these global variables concerns me. It seems that these + make the code a lot easier to break by new programmers. */ int g10_errors_seen = 0; @@ -397,13 +403,19 @@ static char *build_list( const char *text, const char *(*mapf)(int), int (*chkf)(int) ); -static void set_cmd( enum cmd_and_opt_values *ret_cmd, +void set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ); static void print_hex( byte *p, size_t n ); static void print_mds( const char *fname, int algo ); static void add_notation_data( const char *string ); static int check_policy_url( const char *s ); +int init_gpg(void); +void init_secmem_build(void); +void init_options(char *, char *, char *, char *); +void init_keyring(enum cmd_and_opt_values cmd, int argc, STRLIST sec_nrings, + int default_keyring, STRLIST nrings); + const char * strusage( int level ) { @@ -543,8 +555,7 @@ } - -static void +void set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) { enum cmd_and_opt_values cmd = *ret_cmd; @@ -569,55 +580,59 @@ } +/** This function has been added by Mikal in order to implement the API + functionality for GPG */ -int -main( int argc, char **argv ) -{ - ARGPARSE_ARGS pargs; - IOBUF a; - int rc=0; - int orig_argc; - char **orig_argv; - const char *fname; - char *username; +void init_api(){ + init_gpg(); + init_secmem_build(); +} + +int init_gpg(){ int may_coredump; - STRLIST sl, remusr= NULL, locusr=NULL; - STRLIST nrings=NULL, sec_nrings=NULL; - armor_filter_context_t afx; - int detached_sig = 0; - FILE *configfp = NULL; - char *configname = NULL; - unsigned configlineno; - int parse_debug = 0; - int default_config =1; - int default_keyring = 1; - int greeting = 0; - int nogreeting = 0; - int use_random_seed = 1; - enum cmd_and_opt_values cmd = 0; - const char *trustdb_name = NULL; - char *def_cipher_string = NULL; - char *def_digest_string = NULL; - char *s2k_cipher_string = NULL; - char *s2k_digest_string = NULL; - int pwfd = -1; - int with_fpr = 0; /* make an option out of --fingerprint */ - #ifdef USE_SHM_COPROCESSING - ulong requested_shm_size=0; - #endif + /** trap_unaligned does some stuff on some Linux Alpha machines */ trap_unaligned(); + + /** Stop warning the user about secure memory for a bit */ secmem_set_flags( secmem_get_flags() | 2 ); /* suspend warnings */ + /* Please note that we may running SUID(ROOT), so be very CAREFUL * when adding any stuff between here and the call to * secmem_init() somewhere after the option parsing */ + + /** This sets the name of the application that is being logged. + GPG does not use syslog, I am not sure why. This might be because it + is not available on all platforms, but it shouldn't be too hard to + determine which platforms it is available for and then use it. The + other option is because it is not nessesarily good to report to root + problems with a user's copy of gpg on an untrusted machine. + + Perhaps it should be implemented as an option in the config file + for gpg... */ log_set_name("gpg"); + + /** Set a variable in util/random.c so that a random number will be + allocated to the secure memory */ secure_random_alloc(); /* put random number into secure memory */ + + /** may_coredump will either be zero (if coredumping is disabled), + or one if it is enabled */ may_coredump = disable_core_dumps(); + + /** Setup signals for systems that have them */ init_signals(); + + /** create_dotlock called with a NULL arguement installs the atexit + handler to remove the lock files when we are all done */ create_dotlock(NULL); /* register locking cleanup */ + + /** International support using the GNU gettext library */ i18n_init(); + + /** A whole bunch of option stuff -- these are the default processing + options that both the UI and the API use */ opt.command_fd = -1; /* no command fd */ opt.compress = -1; /* defaults to standard compress level */ /* note: if you change these lines, look at oOpenPGP */ @@ -641,12 +656,154 @@ opt.homedir = GNUPG_HOMEDIR; } + return may_coredump; +} + +void init_secmem_build(){ + /* initialize the secure memory. */ + secmem_init( 16384 ); + + /** The secmem_init routine either drops the suid bit of the application, + or returns an error. We can there gaurantee that we are no longer + suid */ + maybe_setuid = 0; + /* Okay, we are now working under our real uid */ +} + +void init_options(char *def_cipher_string, char *def_digest_string, + char *s2k_cipher_string, char *s2k_digest_string){ + /** At the start of main() we disabled secure memory warnings. Now we + turn them back on */ + secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */ + + + set_debug(); + g10_opt_homedir = opt.homedir; + + /* must do this after dropping setuid, because string_to... + * may try to load an module */ + if( def_cipher_string ) { + opt.def_cipher_algo = string_to_cipher_algo(def_cipher_string); + m_free(def_cipher_string); def_cipher_string = NULL; + if( check_cipher_algo(opt.def_cipher_algo) ) + log_error(_("selected cipher algorithm is invalid\n")); + } + if( def_digest_string ) { + opt.def_digest_algo = string_to_digest_algo(def_digest_string); + m_free(def_digest_string); def_digest_string = NULL; + if( check_digest_algo(opt.def_digest_algo) ) + log_error(_("selected digest algorithm is invalid\n")); + } + if( s2k_cipher_string ) { + opt.s2k_cipher_algo = string_to_cipher_algo(s2k_cipher_string); + m_free(s2k_cipher_string); s2k_cipher_string = NULL; + if( check_cipher_algo(opt.s2k_cipher_algo) ) + log_error(_("selected cipher algorithm is invalid\n")); + } + if( s2k_digest_string ) { + opt.s2k_digest_algo = string_to_digest_algo(s2k_digest_string); + m_free(s2k_digest_string); s2k_digest_string = NULL; + if( check_digest_algo(opt.s2k_digest_algo) ) + log_error(_("selected digest algorithm is invalid\n")); + } + if( opt.set_policy_url ) { + if( check_policy_url( opt.set_policy_url ) ) + log_error(_("the given policy URL is invalid\n")); + } + if( opt.def_compress_algo < 1 || opt.def_compress_algo > 2 ) + log_error(_("compress algorithm must be in range %d..%d\n"), 1, 2); + if( opt.completes_needed < 1 ) + log_error(_("completes-needed must be greater than 0\n")); + if( opt.marginals_needed < 2 ) + log_error(_("marginals-needed must be greater than 1\n")); + if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 ) + log_error(_("max-cert-depth must be in range 1 to 255\n")); + switch( opt.s2k_mode ) { + case 0: + log_info(_("NOTE: simple S2K mode (0) is strongly discouraged\n")); + break; + case 1: case 3: break; + default: + log_error(_("invalid S2K mode; must be 0, 1 or 3\n")); + } +} + +void init_keyring(enum cmd_and_opt_values cmd, int argc, STRLIST sec_nrings, + int default_keyring, STRLIST nrings){ + STRLIST sl; + + /* add the keyrings, but not for some special commands and + * not in case of "-kvv userid keyring" */ + if( cmd != aDeArmor && cmd != aEnArmor + && !(cmd == aKMode && argc == 2 ) ) { + + if( !sec_nrings && default_keyring ) /* add default secret rings */ + add_keyblock_resource("secring.gpg", 0, 1); + for(sl = sec_nrings; sl; sl = sl->next ) + add_keyblock_resource( sl->d, 0, 1 ); + if( !nrings && default_keyring ) /* add default ring */ + add_keyblock_resource("pubring.gpg", 0, 0); + for(sl = nrings; sl; sl = sl->next ) + add_keyblock_resource( sl->d, 0, 0 ); + } + FREE_STRLIST(nrings); + FREE_STRLIST(sec_nrings); +} + +int +ui_main( int argc, char **argv ) +{ + /** This variable is used by the gpg init code that used to be in main(), + but is now here */ + int may_coredump; + + ARGPARSE_ARGS pargs; + IOBUF a; + int rc=0; + int orig_argc; + char **orig_argv; + const char *fname; + char *username; + STRLIST nrings=NULL, sec_nrings=NULL; + armor_filter_context_t afx; + int detached_sig = 0; + FILE *configfp = NULL; + char *configname = NULL; + unsigned configlineno; + STRLIST sl, remusr= NULL, locusr=NULL; + int parse_debug = 0; + int default_config =1; + int default_keyring = 1; + int greeting = 0; + int nogreeting = 0; + int use_random_seed = 1; + enum cmd_and_opt_values cmd = 0; + const char *trustdb_name = NULL; + char *def_cipher_string = NULL; + char *def_digest_string = NULL; + char *s2k_cipher_string = NULL; + char *s2k_digest_string = NULL; + int pwfd = -1; + int with_fpr = 0; /* make an option out of --fingerprint */ + #ifdef USE_SHM_COPROCESSING + ulong requested_shm_size=0; + #endif + + /** This is the main function for the gpg user interface */ + may_coredump = init_gpg(); + + /** Save the arguements we were handed, and build something for the + ARGPARSE command to use. ARGPARSE is a replacement for getopt(). + We repeatedly call arg_parse until we have run out of possible + arguements to parse. r_opt is the option that has been returned + to us */ /* check whether we have a config file on the commandline */ orig_argc = argc; orig_argv = argv; pargs.argc = &argc; pargs.argv = &argv; pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ + while( arg_parse( &pargs, opts) ) { if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll ) parse_debug++; @@ -681,14 +838,18 @@ init_shm_coprocessing(requested_shm_size, 1 ); } #endif - /* initialize the secure memory. */ - secmem_init( 16384 ); - maybe_setuid = 0; - /* Okay, we are now working under our real uid */ + + /** End of the command line arguement parsing code */ + + /** Some code has been moved from here so that the API functionality can + be worked on */ + init_secmem_build(); if( default_config ) configname = make_filename(opt.homedir, "options", NULL ); + /** Go through the whole option parsing thing again, but this time as + something that is not suid */ argc = orig_argc; argv = orig_argv; pargs.argc = &argc; @@ -716,6 +877,7 @@ default_config = 0; } + /** Parse the options file */ while( optfile_parse( configfp, configname, &configlineno, &pargs, opts) ) { switch( pargs.r_opt ) { @@ -941,15 +1103,24 @@ default : pargs.err = configfp? 1:2; break; } } + + /** If we opened a config file, then we should clean up after ourselves */ if( configfp ) { fclose( configfp ); configfp = NULL; m_free(configname); configname = NULL; goto next_pass; } + + /** And free up some memory */ m_free( configname ); configname = NULL; + + /** If we experienced errors, then we should exit */ if( log_get_errorcount(0) ) g10_exit(2); + + /** Huh? Why introduce the greeting variable here??? Otherwise, just + print a greeting message */ if( nogreeting ) greeting = 0; @@ -958,6 +1129,9 @@ strusage(11), strusage(13), strusage(14) ); fprintf(stderr, "%s\n", strusage(15) ); } + + /* If this is a development version, then do some stuff we wouldn't + otherwise do */ #ifdef IS_DEVELOPMENT_VERSION if( !opt.batch ) { log_info("NOTE: THIS IS A DEVELOPMENT VERSION!\n"); @@ -966,10 +1140,12 @@ } #endif + /** If we are allowed to, we should warn about our inability to disable + core dumping */ if( may_coredump && !opt.quiet ) log_info(_("WARNING: program may create a core file!\n")); - + /** I am not sure what --no-literal and --set-filesize do */ if (opt.no_literal) { log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal"); if (opt.textmode) @@ -984,58 +1160,9 @@ if( opt.batch ) tty_batchmode( 1 ); - secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */ - - set_debug(); - g10_opt_homedir = opt.homedir; - - /* must do this after dropping setuid, because string_to... - * may try to load an module */ - if( def_cipher_string ) { - opt.def_cipher_algo = string_to_cipher_algo(def_cipher_string); - m_free(def_cipher_string); def_cipher_string = NULL; - if( check_cipher_algo(opt.def_cipher_algo) ) - log_error(_("selected cipher algorithm is invalid\n")); - } - if( def_digest_string ) { - opt.def_digest_algo = string_to_digest_algo(def_digest_string); - m_free(def_digest_string); def_digest_string = NULL; - if( check_digest_algo(opt.def_digest_algo) ) - log_error(_("selected digest algorithm is invalid\n")); - } - if( s2k_cipher_string ) { - opt.s2k_cipher_algo = string_to_cipher_algo(s2k_cipher_string); - m_free(s2k_cipher_string); s2k_cipher_string = NULL; - if( check_cipher_algo(opt.s2k_cipher_algo) ) - log_error(_("selected cipher algorithm is invalid\n")); - } - if( s2k_digest_string ) { - opt.s2k_digest_algo = string_to_digest_algo(s2k_digest_string); - m_free(s2k_digest_string); s2k_digest_string = NULL; - if( check_digest_algo(opt.s2k_digest_algo) ) - log_error(_("selected digest algorithm is invalid\n")); - } - if( opt.set_policy_url ) { - if( check_policy_url( opt.set_policy_url ) ) - log_error(_("the given policy URL is invalid\n")); - } - if( opt.def_compress_algo < 1 || opt.def_compress_algo > 2 ) - log_error(_("compress algorithm must be in range %d..%d\n"), 1, 2); - if( opt.completes_needed < 1 ) - log_error(_("completes-needed must be greater than 0\n")); - if( opt.marginals_needed < 2 ) - log_error(_("marginals-needed must be greater than 1\n")); - if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 ) - log_error(_("max-cert-depth must be in range 1 to 255\n")); - switch( opt.s2k_mode ) { - case 0: - log_info(_("NOTE: simple S2K mode (0) is strongly discouraged\n")); - break; - case 1: case 3: break; - default: - log_error(_("invalid S2K mode; must be 0, 1 or 3\n")); - } - + /** Some more moved code */ + init_options(def_cipher_string, def_digest_string, s2k_cipher_string, + s2k_digest_string); if( log_get_errorcount(0) ) g10_exit(2); @@ -1074,23 +1201,8 @@ if( opt.verbose > 1 ) set_packet_list_mode(1); - /* add the keyrings, but not for some special commands and - * not in case of "-kvv userid keyring" */ - if( cmd != aDeArmor && cmd != aEnArmor - && !(cmd == aKMode && argc == 2 ) ) { - - if( !sec_nrings && default_keyring ) /* add default secret rings */ - add_keyblock_resource("secring.gpg", 0, 1); - for(sl = sec_nrings; sl; sl = sl->next ) - add_keyblock_resource( sl->d, 0, 1 ); - if( !nrings && default_keyring ) /* add default ring */ - add_keyblock_resource("pubring.gpg", 0, 0); - for(sl = nrings; sl; sl = sl->next ) - add_keyblock_resource( sl->d, 0, 0 ); - } - FREE_STRLIST(nrings); - FREE_STRLIST(sec_nrings); - + /** Moved this code as well */ + init_keyring(cmd, argc, sec_nrings, default_keyring, nrings); if( pwfd != -1 ) /* read the passphrase now. */ read_passphrase_from_fd( pwfd ); diff -u gnupg-1.0.3/g10/misc.c gnupg-api/g10/misc.c --- gnupg-1.0.3/g10/misc.c Sat Nov 4 10:46:00 2000 +++ gnupg-api/g10/misc.c Thu Oct 19 19:27:24 2000 @@ -52,6 +52,10 @@ g10u_revision_string(0); } +/** The trap_unaligned call seems to only do things on Alpha Linux boxes + running something greater than or equal to glibc version two. I surmise + that this is something to do with 64 bit operations, but this is only + a guess. */ #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #warning using trap_unaligned @@ -72,19 +76,25 @@ setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0); } #else + +/** On any other platform we don't do anything at all... */ + void trap_unaligned(void) { /* dummy */ } #endif - +/** Work out how to disable core dumps */ int disable_core_dumps() { + /** DOS doesn't have the concept of core dumps, so hey, it's easy */ #ifdef HAVE_DOSISH_SYSTEM return 0; #else + /** Otherwise we need to use the setrlimit(2) call to make sure the maximum + core size is zero */ #ifdef HAVE_SETRLIMIT struct rlimit limit; @@ -93,8 +103,12 @@ if( !setrlimit( RLIMIT_CORE, &limit ) ) return 0; if( errno != EINVAL && errno != ENOSYS ) + /** We really care if we cannot disable core dumping, as this is a + security hole... */ log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) ); #endif + + /** Hey, just let it core dump */ return 1; #endif } diff -u gnupg-1.0.3/g10/options.skel gnupg-api/g10/options.skel --- gnupg-1.0.3/g10/options.skel Sat Nov 4 10:46:02 2000 +++ gnupg-api/g10/options.skel Thu Oct 19 16:38:53 2000 @@ -1,6 +1,6 @@ These first three lines are not copied to the options file in the users home directory. -$Id: options.skel,v 1.12.2.1 1999/10/08 18:34:41 wkoch Exp $ +$Id: options.skel,v 1.1.1.1 2000/10/19 05:38:53 root Exp $ # Options for GnuPG # # Unless you you specify which option file to use (with the diff -u gnupg-1.0.3/g10/passphrase.c gnupg-api/g10/passphrase.c --- gnupg-1.0.3/g10/passphrase.c Sat Nov 4 10:46:00 2000 +++ gnupg-api/g10/passphrase.c Mon Oct 23 16:25:28 2000 @@ -33,6 +33,9 @@ #include "main.h" #include "i18n.h" #include "status.h" +#include "api.h" + +extern gpg_mtoken apimagic; static char *fd_passwd = NULL; static char *next_pw = NULL; @@ -118,7 +121,7 @@ */ DEK * passphrase_to_dek( u32 *keyid, int pubkey_algo, - int cipher_algo, STRING2KEY *s2k, int mode ) + int cipher_algo, STRING2KEY *s2k, int mode) { char *pw = NULL; DEK *dek; @@ -156,26 +159,29 @@ size_t n; char *p; - tty_printf(_("\nYou need a passphrase to unlock the secret key for\n" - "user: \"") ); - p = get_user_id( keyid, &n ); - tty_print_utf8_string( p, n ); - m_free(p); - tty_printf("\"\n"); + if(apimagic.passphrase == NULL){ + tty_printf(_("\nYou need a passphrase to unlock the secret key for\n" + "user: \"") ); + p = get_user_id( keyid, &n ); + tty_print_utf8_string( p, n ); + m_free(p); + tty_printf("\"\n"); + - if( !get_pubkey( pk, keyid ) ) { + if( !get_pubkey( pk, keyid ) ) { const char *s = pubkey_algo_to_string( pk->pubkey_algo ); tty_printf( _("%u-bit %s key, ID %08lX, created %s"), - nbits_from_pk( pk ), s?s:"?", (ulong)keyid[1], - strtimestamp(pk->timestamp) ); + nbits_from_pk( pk ), s?s:"?", (ulong)keyid[1], + strtimestamp(pk->timestamp) ); if( keyid[2] && keyid[3] && keyid[0] != keyid[2] - && keyid[1] != keyid[3] ) - tty_printf( _(" (main key ID %08lX)"), (ulong)keyid[3] ); + && keyid[1] != keyid[3] ) + tty_printf( _(" (main key ID %08lX)"), (ulong)keyid[3] ); tty_printf("\n"); - } + } - tty_printf("\n"); - free_public_key( pk ); + tty_printf("\n"); + free_public_key( pk ); + } } if( next_pw ) { @@ -191,7 +197,10 @@ pw = m_strdup( "" ); /* return an empty passphrase */ } else { + if(apimagic.passphrase == NULL) pw = cpr_get_hidden("passphrase.enter", _("Enter passphrase: ") ); + else pw = apimagic.passphrase; + tty_kill_prompt(); if( mode == 2 && !cpr_enabled() ) { char *pw2 = cpr_get_hidden("passphrase.repeat", diff -u gnupg-1.0.3/g10/signal.c gnupg-api/g10/signal.c --- gnupg-1.0.3/g10/signal.c Sat Nov 4 10:46:00 2000 +++ gnupg-api/g10/signal.c Thu Oct 19 19:27:24 2000 @@ -86,6 +86,10 @@ } #ifndef HAVE_DOSISH_SYSTEM + +/** If this is a system with signals, then we check if the signal is ignored + at the moment, then we continue to ignore it. Otherwise, we start doing + whatever action we were just asked to do */ static void do_sigaction( int sig, struct sigaction *nact ) { @@ -97,16 +101,20 @@ } #endif +/** Define what actions should be taken for several types of signals */ void init_signals() { #ifndef HAVE_DOSISH_SYSTEM + /** MS systems don't have signals */ struct sigaction nact; nact.sa_handler = got_fatal_signal; sigemptyset( &nact.sa_mask ); nact.sa_flags = 0; - + + /** For each of the signals, we call do_sigaction, which will set the + action to what we specify if the signal is not currently ignored */ do_sigaction( SIGINT, &nact ); do_sigaction( SIGHUP, &nact ); do_sigaction( SIGTERM, &nact );