Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler.
Number of rules (primarily dangerous function names) in C/C++ ruleset: 223
Examining data/lxsession-0.5.5/lxsession-logout/lxsession-logout-dbus-interface.h
Examining data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c
Examining data/lxsession-0.5.5/lxsession-logout/lxsession-logout-dbus-interface.c
Examining data/lxsession-0.5.5/lxsession-default-apps/dbus-backend.c
Examining data/lxsession-0.5.5/lxsession-default-apps/utils.c
Examining data/lxsession-0.5.5/lxsession-default-apps/main.c
Examining data/lxsession-0.5.5/lxsession-default-apps/combobox.c
Examining data/lxsession-0.5.5/lxsession-default-apps/autostart.c
Examining data/lxsession-0.5.5/lxsession-db/desktop-files-backend.c
Examining data/lxsession-0.5.5/lxsession-db/main.c
Examining data/lxsession-0.5.5/xdg-autostart/xdg-autostart.c
Examining data/lxsession-0.5.5/xdg-autostart/xdg-autostart.h
Examining data/lxsession-0.5.5/xdg-autostart/main.c
Examining data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c
Examining data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.h
Examining data/lxsession-0.5.5/lxsettings-daemon/xutils.h
Examining data/lxsession-0.5.5/lxsettings-daemon/xutils.c
Examining data/lxsession-0.5.5/lxsettings-daemon/settings-daemon.c
Examining data/lxsession-0.5.5/lxsettings-daemon/xevent.c
Examining data/lxsession-0.5.5/lxsettings-daemon/main.c
Examining data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.h
Examining data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.c
Examining data/lxsession-0.5.5/lxsettings-daemon/settings-daemon.h
Examining data/lxsession-0.5.5/lxsettings-daemon/xevent.h
Examining data/lxsession-0.5.5/lxpolkit/lxpolkit-listener.h
Examining data/lxsession-0.5.5/lxpolkit/main.c
Examining data/lxsession-0.5.5/lxpolkit/lxpolkit.h
Examining data/lxsession-0.5.5/lxpolkit/lxpolkit.c
Examining data/lxsession-0.5.5/lxpolkit/lxpolkit-listener.c
Examining data/lxsession-0.5.5/lxclipboard/clipboard.c
Examining data/lxsession-0.5.5/lxclipboard/clipboard.h
Examining data/lxsession-0.5.5/lxclipboard/main.c
Examining data/lxsession-0.5.5/lxsession/dbus-gnome-session.c
Examining data/lxsession-0.5.5/lxsession/app.c
Examining data/lxsession-0.5.5/lxsession/dbus-lxde-session.c
Examining data/lxsession-0.5.5/lxsession/conffiles.c
Examining data/lxsession-0.5.5/lxsession/process.c
Examining data/lxsession-0.5.5/lxsession/utils.c
Examining data/lxsession-0.5.5/lxsession/main.c
Examining data/lxsession-0.5.5/lxsession/options.c
Examining data/lxsession-0.5.5/lxsession/settings.c
Examining data/lxsession-0.5.5/lxsession/environement.c
Examining data/lxsession-0.5.5/lxsession/notifications.c
Examining data/lxsession-0.5.5/lxsession/control.c
Examining data/lxsession-0.5.5/lxsession/autostart.c
Examining data/lxsession-0.5.5/lxsession/dbus-common.c
Examining data/lxsession-0.5.5/lxsession-edit/lxsession-edit-common.c
Examining data/lxsession-0.5.5/lxsession-edit/lxsession-edit.c
Examining data/lxsession-0.5.5/lxsession-edit/lxsession-edit-common.h

FINAL RESULTS:

data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:147:9:  [4] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf.
        sprintf(buffer, "/var/run/%s.pid", display_manager);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:150:13:  [4] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf.
            sprintf(buffer, "/var/run/%s/%s.pid", display_manager, display_manager);
data/lxsession-0.5.5/lxsession-default-apps/combobox.c:3481:11:  [3] (buffer) g_get_home_dir:
  This function is synonymous with 'getenv("HOME")';it returns untrustable
  input if the environment can beset by an attacker. It can have any content
  and length, and the same variable can be set more than once (CWE-807,
  CWE-20). Check environment variables carefully before using them.
	_tmp0_ = g_get_home_dir ();
data/lxsession-0.5.5/lxsession/conffiles.c:416:11:  [3] (buffer) g_get_home_dir:
  This function is synonymous with 'getenv("HOME")';it returns untrustable
  input if the environment can beset by an attacker. It can have any content
  and length, and the same variable can be set more than once (CWE-807,
  CWE-20). Check environment variables carefully before using them.
	_tmp6_ = g_get_home_dir ();
data/lxsession-0.5.5/lxsession/dbus-gnome-session.c:499:20:  [3] (random) g_random_int:
  This function is not sufficiently random for security-related functions
  such as key and nonce creation (CWE-327). Use a more secure technique for
  acquiring random values.
		_data_->_tmp4_ = g_random_int ();
data/lxsession-0.5.5/lxclipboard/clipboard.c:421:25:  [2] (buffer) memcpy:
  Does not check for buffer overflows when copying to destination (CWE-120).
  Make sure destination can always hold the source data.
                        memcpy (tdata->data + tdata->length, data, length + 1);
data/lxsession-0.5.5/lxsession-default-apps/main.c:3573:12:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
	_tmp16_ = open (_tmp15_, (O_WRONLY | O_CREAT) | O_TRUNC, (mode_t) 0600);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:146:9:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
        char buffer[PATH_MAX];
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:153:18:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
        int fd = open(buffer, O_RDONLY);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:163:29:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
                pid_t pid = atoi(buffer);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:169:21:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
                    sprintf(buffer, "/proc/%d/cmdline", pid);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:172:30:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
                    int fd = open(buffer, O_RDONLY);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:469:8:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
static char lockfile[PATH_MAX];
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:492:52:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
    if (p != NULL) handler_context.lxsession_pid = atoi(p);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:495:5:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
    sprintf(lockfile, "/tmp/.lxsession-logout-%d.lock", handler_context.lxsession_pid);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:496:14:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
    int fd = open(lockfile, O_RDONLY|O_CREAT, 00600);
data/lxsession-0.5.5/lxsession/app.c:5648:15:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
				_tmp10_ = atoi (_tmp9_);
data/lxsession-0.5.5/lxsession/app.c:6530:14:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
			_tmp72_ = atoi (_tmp71_);
data/lxsession-0.5.5/lxsession/app.c:6535:14:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
			_tmp75_ = atoi (_tmp74_);
data/lxsession-0.5.5/lxsession/app.c:6956:11:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
	_tmp3_ = open (_tmp2_, O_RDWR, (mode_t) 0);
data/lxsession-0.5.5/lxsession/app.c:7306:13:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
			_tmp8_ = atoi (_tmp7_);
data/lxsession-0.5.5/lxsession/main.c:935:12:  [2] (misc) open:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
	_tmp32_ = open (_tmp31_, (O_WRONLY | O_CREAT) | O_TRUNC, (mode_t) 0600);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.c:46:3:  [2] (buffer) memcpy:
  Does not check for buffer overflows when copying to destination (CWE-120).
  Make sure destination can always hold the source data.
  memcpy (result->name, setting->name, str_len + 1);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.c:64:7:  [2] (buffer) memcpy:
  Does not check for buffer overflows when copying to destination (CWE-120).
  Make sure destination can always hold the source data.
      memcpy (result->data.v_string, setting->data.v_string, str_len + 1);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:107:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char buffer[256];
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:110:3:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
  sprintf(buffer, "_XSETTINGS_S%d", screen);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:129:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char buffer[256];
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:138:3:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
  sprintf(buffer, "_XSETTINGS_S%d", screen);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:335:3:  [2] (buffer) memcpy:
  Does not check for buffer overflows when copying to destination (CWE-120).
  Make sure destination can always hold the source data.
  memcpy (buffer->pos, setting->name, string_len);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:360:7:  [2] (buffer) memcpy:
  Does not check for buffer overflows when copying to destination (CWE-120).
  Make sure destination can always hold the source data.
      memcpy (buffer->pos, setting->data.v_string, string_len);
data/lxsession-0.5.5/lxsession-db/desktop-files-backend.c:2552:12:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp3_ = strlen (str);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:338:12:  [1] (buffer) fgetc:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
		_tmp0_ = fgetc (self);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:397:11:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
	_tmp0_ = strlen (self);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:940:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:942:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_tmp35_ = read;
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:946:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_tmp36_ = read;
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:950:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_tmp38_ = read;
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:961:16:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
					_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:975:15:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
				_tmp44_ = read;
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:978:16:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
					_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:990:16:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
					_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:1011:15:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
				_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:1025:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:1037:14:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
			_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/autostart.c:1048:13:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
		_g_free0 (read);
data/lxsession-0.5.5/lxsession-default-apps/combobox.c:1109:11:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
	_tmp0_ = strlen (self);
data/lxsession-0.5.5/lxsession-default-apps/combobox.c:3553:13:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp24_ = strlen (str);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:157:30:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
            ssize_t length = read(fd, buffer, sizeof(buffer));
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:176:42:  [1] (buffer) read:
  Check buffer boundaries if used in a loop including recursive loops
  (CWE-120, CWE-20).
                        ssize_t length = read(fd, buffer, sizeof(buffer));
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:216:64:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
                      PropModeReplace, (unsigned char*) value, strlen(value) + 1);
data/lxsession-0.5.5/lxsession-logout/lxsession-logout.c:742:20:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
            output[strlen ( output ) - 1] = '\0';
data/lxsession-0.5.5/lxsession/app.c:5974:12:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp8_ = strlen (standard_output);
data/lxsession-0.5.5/lxsession/app.c:6156:11:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
	_tmp0_ = strlen (self);
data/lxsession-0.5.5/lxsession/app.c:6455:14:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
			_tmp50_ = strlen (standard_error);
data/lxsession-0.5.5/lxsession/autostart.c:156:11:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
	_tmp0_ = strlen (self);
data/lxsession-0.5.5/lxsession/settings.c:3027:12:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp3_ = strlen (str);
data/lxsession-0.5.5/lxsession/settings.c:3120:14:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
			_tmp19_ = strlen (str);
data/lxsession-0.5.5/lxsession/settings.c:4283:13:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp30_ = strlen (str_session);
data/lxsession-0.5.5/lxsession/settings.c:4325:13:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
		_tmp37_ = strlen (str_conf);
data/lxsession-0.5.5/lxsettings-daemon/settings-daemon.c:72:39:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
            w = write( stdi, content, strlen(content));
data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.c:41:13:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
  str_len = strlen (setting->name);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-common.c:59:17:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
      str_len = strlen (setting->data.v_string);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:302:28:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
  length += XSETTINGS_PAD (strlen (setting->name), 4);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:310:36:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
      length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:330:16:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
  string_len = strlen (setting->name);
data/lxsession-0.5.5/lxsettings-daemon/xsettings-manager.c:355:20:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
      string_len = strlen (setting->data.v_string);

ANALYSIS SUMMARY:

Hits = 66
Lines analyzed = 47288 in approximately 1.04 seconds (45498 lines/second)
Physical Source Lines of Code (SLOC) = 42384
Hits@level = [0]  12 [1]  36 [2]  25 [3]   3 [4]   2 [5]   0
Hits@level+ = [0+]  78 [1+]  66 [2+]  30 [3+]   5 [4+]   2 [5+]   0
Hits/KSLOC@level+ = [0+] 1.84032 [1+] 1.55719 [2+] 0.707814 [3+] 0.117969 [4+] 0.0471876 [5+]   0
Dot directories skipped = 1 (--followdotdir overrides)
Minimum risk level = 1
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!
See 'Secure Programming HOWTO'
(https://dwheeler.com/secure-programs) for more information.