DES crypt is trivially crackable. Passwords starting with $ are now
auto-detected as crypt hashes (supports $5$ SHA-256, $6$ SHA-512, etc).
Plaintext passwords still work for backwards compatibility.
Remove crypt_oper_password and crypt_iline_password config options —
detection is now automatic based on the $ prefix in stored passwords.
Update mkpasswd to generate SHA-256 ($5$) hashes with random salts.
Stop logging passwords (plaintext or hashed) in oper logs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Defines who has Oper access on the server.
#
# host - Address mask the oper must connect from.
# Defines who has Oper access on the server.
#
# host - Address mask the oper must connect from.
-# password - Oper password (use mkpasswd if compiled with encryption).
+# password - Oper password. Use mkpasswd to generate a SHA-256 hash,
+# or use plaintext. Hashed passwords start with $5$.
# name - Oper nickname.
# flags - Access flags (see below).
# class - Connection class number.
# name - Oper nickname.
# flags - Access flags (see below).
# class - Connection class number.
# hub - Enable hub mode (accepts multiple server links).
# throttle - Enable clone/throttle detection (yes/no).
# seeuserstats - Show user stat notifications to opers (yes/no).
# hub - Enable hub mode (accepts multiple server links).
# throttle - Enable clone/throttle detection (yes/no).
# seeuserstats - Show user stat notifications to opers (yes/no).
-# crypt_oper_password - Oper passwords are encrypted (yes/no).
-# crypt_iline_password - I-line passwords are encrypted (yes/no).
#
general {
# hub yes;
throttle yes;
seeuserstats yes;
#
general {
# hub yes;
throttle yes;
seeuserstats yes;
- crypt_oper_password yes;
- crypt_iline_password yes;
-/* simple password generator by Nelson Minar (minar@reed.edu)
- * copyright 1991, all rights reserved.
- * You can use this code as long as my name stays with it.
+/* mkpasswd - generate SHA-256 password hashes for ircd.conf
+ *
+ * Originally by Nelson Minar (minar@reed.edu), updated for SHA-256.
+ * Usage: mkpasswd [salt]
+ * Without arguments, generates a random salt.
+ * With an argument, uses it as the salt.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
+#include <unistd.h>
-extern char *getpass();
-
-int main(argc, argv)
-int argc;
-char *argv[];
+int main(int argc, char *argv[])
- static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
- char salt[3];
- char * plaintext;
- int i;
-
- if (argc < 2) {
- srandom(time(0)); /* may not be the BEST salt, but its close */
- salt[0] = saltChars[random() % 64];
- salt[1] = saltChars[random() % 64];
- salt[2] = 0;
- }
- else {
- salt[0] = argv[1][0];
- salt[1] = argv[1][1];
- salt[2] = '\0';
- if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL))
- fprintf(stderr, "illegal salt %s\n", salt), exit(1);
- }
+ static const char saltchars[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+ char salt[24];
+ char *plaintext;
+ char *hash;
+ int i;
- plaintext = getpass("plaintext: ");
+ /* Build $5$........$ salt (SHA-256) */
+ strcpy(salt, "$5$");
+ if (argc >= 2) {
+ strncat(salt, argv[1], 16);
+ } else {
+ srandom(time(NULL) ^ getpid());
+ for (i = 0; i < 16; i++)
+ salt[3 + i] = saltchars[random() % 64];
+ salt[19] = '\0';
+ }
+ strcat(salt, "$");
- printf("%s\n", crypt(plaintext, salt));
- return 0;
+ plaintext = getpass("plaintext: ");
+ hash = crypt(plaintext, salt);
+ if (!hash || hash[0] == '*') {
+ fprintf(stderr, "crypt() failed — SHA-256 may not be supported\n");
+ return 1;
+ }
+ printf("%s\n", hash);
+ return 0;
anUser *user = sptr->user;
aClient *nsptr;
int i;
anUser *user = sptr->user;
aClient *nsptr;
int i;
extern char *crypt ();
user->last = time (NULL);
extern char *crypt ();
user->last = time (NULL);
u1 = NULL;
if (!BadPtr (aconf->passwd)) {
u1 = NULL;
if (!BadPtr (aconf->passwd)) {
- if (cfg_crypt_iline_password) {
- /* use first two chars of the password they send in as salt */
- /* passwd may be NULL. Head it off at the pass... */
- salt[0] = '\0';
- if (sptr->passwd && aconf->passwd && aconf->passwd[0] &&
- aconf->passwd[1]) {
- salt[0] = aconf->passwd[0];
- salt[1] = aconf->passwd[1];
- salt[2] = '\0';
- encr = crypt (sptr->passwd, salt);
- }
- else
- encr = "";
- } else
- encr = sptr->passwd;
+ /* If stored password starts with $, it's a crypt hash —
+ * use it as the salt so crypt auto-detects the algorithm.
+ * Otherwise compare plaintext. */
+ if (sptr->passwd && aconf->passwd[0] == '$')
+ encr = crypt (sptr->passwd, aconf->passwd);
+ else
+ encr = sptr->passwd ? sptr->passwd : "";
- if (!StrEq (encr, aconf->passwd)) {
+ if (!encr || !StrEq (encr, aconf->passwd)) {
ircstp->is_ref++;
sendto_one (sptr, err_str (ERR_PASSWDMISMATCH), me.name,
parv[0]);
ircstp->is_ref++;
sendto_one (sptr, err_str (ERR_PASSWDMISMATCH), me.name,
parv[0]);
{
aConfItem *aconf;
char *name, *password, *encr;
{
aConfItem *aconf;
char *name, *password, *encr;
extern char *crypt ();
if (check_registered_user (sptr))
extern char *crypt ();
if (check_registered_user (sptr))
sptr->since += 7;
return 0;
}
sptr->since += 7;
return 0;
}
- if (cfg_crypt_oper_password) {
- /* use first two chars of the password they send in as salt */
- /* passwd may be NULL. Head it off at the pass... */
- salt[0] = '\0';
- if (password && aconf->passwd && aconf->passwd[0] && aconf->passwd[1]) {
- salt[0] = aconf->passwd[0];
- salt[1] = aconf->passwd[1];
- salt[2] = '\0';
- encr = crypt (password, salt);
- }
- else
- encr = "";
- } else
- encr = password;
+ /* If stored password starts with $, it's a crypt hash —
+ * use it as the salt so crypt auto-detects the algorithm.
+ * Otherwise compare plaintext. */
+ if (password && aconf->passwd && aconf->passwd[0] == '$')
+ encr = crypt (password, aconf->passwd);
+ else
+ encr = password ? password : "";
if ((aconf->status & CONF_OPS) &&
if ((aconf->status & CONF_OPS) &&
- StrEq (encr, aconf->passwd) && !attach_conf (sptr, aconf)) {
+ encr && StrEq (encr, aconf->passwd) && !attach_conf (sptr, aconf)) {
int old = (sptr->umodes & ALL_UMODES);
char *s;
int old = (sptr->umodes & ALL_UMODES);
char *s;
calc_mask(sptr) ;
(void) m_opermotd (sptr, sptr, 1, parv);
calc_mask(sptr) ;
(void) m_opermotd (sptr, sptr, 1, parv);
- if (!cfg_crypt_oper_password)
- encr = "";
#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
- syslog (LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s)",
- name, encr, parv[0], sptr->user->username, sptr->sockhost);
+ syslog (LOG_INFO, "OPER (%s) by (%s!%s@%s)",
+ name, parv[0], sptr->user->username, sptr->sockhost);
#endif
#ifdef FNAME_OPERLOG
{
#endif
#ifdef FNAME_OPERLOG
{
*/
if (IsPerson (sptr) &&
(logfile = open (FNAME_OPERLOG, O_WRONLY | O_APPEND)) != -1) {
*/
if (IsPerson (sptr) &&
(logfile = open (FNAME_OPERLOG, O_WRONLY | O_APPEND)) != -1) {
- (void) sprintf (buf, "%s OPER (%s) (%s) by (%s!%s@%s)\n",
- myctime (time (NULL)), name, encr,
+ (void) sprintf (buf, "%s OPER (%s) by (%s!%s@%s)\n",
+ myctime (time (NULL)), name,
parv[0], sptr->user->username,
sptr->sockhost);
(void) write (logfile, buf, strlen (buf));
parv[0], sptr->user->username,
sptr->sockhost);
(void) write (logfile, buf, strlen (buf));