]> jfr.im git - irc/rizon/znc.git/blame - Utils.cpp
Write forceserver and webircpassword to conf
[irc/rizon/znc.git] / Utils.cpp
CommitLineData
a09a7e79 1/*
b9b0fd4c 2 * Copyright (C) 2004-2011 See the AUTHORS file for details.
a09a7e79 3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 */
6dcacaa7 8
538d3ece 9#include "Utils.h"
6249e41c 10#include "MD5.h"
03896135 11#include "main.h"
ac5c021c 12#include "ZNCDebug.h"
29d8ef89 13#include <errno.h>
46daeeba 14#ifdef HAVE_LIBSSL
15#include <openssl/ssl.h>
16#endif /* HAVE_LIBSSL */
e72c4456 17#include <sstream>
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <unistd.h>
46daeeba 21
9e68cd35 22// Required with GCC 4.3+ if openssl is disabled
23#include <cstring>
24#include <cstdlib>
25
538d3ece 26using std::stringstream;
27
28CUtils::CUtils() {}
29CUtils::~CUtils() {}
30
7627ea11 31#ifdef HAVE_LIBSSL
b03f495b 32void CUtils::GenerateCert(FILE *pOut, const CString& sHost) {
0955474b 33 EVP_PKEY *pKey = NULL;
34 X509 *pCert = NULL;
35 X509_NAME *pName = NULL;
1d88f564 36 const int days = 365;
a0f977d2 37 const int years = 10;
a26fdbdf 38
b0a1714b 39 u_int iSeed = time(NULL);
40 int serial = (rand_r(&iSeed) % 9999);
0955474b 41
3bbe5e7a 42 RSA *pRSA = RSA_generate_key(2048, 0x10001, NULL, NULL);
b0a1714b 43 if ((pKey = EVP_PKEY_new())) {
44 if (!EVP_PKEY_assign_RSA(pKey, pRSA)) {
45 EVP_PKEY_free(pKey);
0955474b 46 return;
47 }
7627ea11 48
b03f495b 49 PEM_write_RSAPrivateKey(pOut, pRSA, NULL, NULL, 0, NULL, NULL);
e233decc 50
c64d7bc1 51 if (!(pCert = X509_new())) {
b0a1714b 52 EVP_PKEY_free(pKey);
0955474b 53 return;
54 }
7627ea11 55
b0a1714b 56 X509_set_version(pCert, 2);
57 ASN1_INTEGER_set(X509_get_serialNumber(pCert), serial);
58 X509_gmtime_adj(X509_get_notBefore(pCert), 0);
a0f977d2 59 X509_gmtime_adj(X509_get_notAfter(pCert), (long)60*60*24*days*years);
b0a1714b 60 X509_set_pubkey(pCert, pKey);
f74ab87e 61
b0a1714b 62 pName = X509_get_subject_name(pCert);
7627ea11 63
bf171597 64 const char *pLogName = getenv("LOGNAME");
65 const char *pHostName = NULL;
66
67 if (!sHost.empty()) {
68 pHostName = sHost.c_str();
69 }
70
71 if (!pHostName) {
72 pHostName = getenv("HOSTNAME");
73 }
7627ea11 74
0955474b 75 if (!pLogName) {
76 pLogName = "Unknown";
77 }
7627ea11 78
0955474b 79 if (!pHostName) {
dcf357b1 80 pHostName = "host.unknown";
0955474b 81 }
e57edc5a 82
0955474b 83 CString sEmailAddr = pLogName;
84 sEmailAddr += "@";
85 sEmailAddr += pHostName;
86
b0a1714b 87 X509_NAME_add_entry_by_txt(pName, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
88 X509_NAME_add_entry_by_txt(pName, "ST", MBSTRING_ASC, (unsigned char *)"SomeState", -1, -1, 0);
89 X509_NAME_add_entry_by_txt(pName, "L", MBSTRING_ASC, (unsigned char *)"SomeCity", -1, -1, 0);
90 X509_NAME_add_entry_by_txt(pName, "O", MBSTRING_ASC, (unsigned char *)"SomeCompany", -1, -1, 0);
91 X509_NAME_add_entry_by_txt(pName, "OU", MBSTRING_ASC, (unsigned char *)pLogName, -1, -1, 0);
92 X509_NAME_add_entry_by_txt(pName, "CN", MBSTRING_ASC, (unsigned char *)pHostName, -1, -1, 0);
93 X509_NAME_add_entry_by_txt(pName, "emailAddress", MBSTRING_ASC, (unsigned char *)sEmailAddr.c_str(), -1, -1, 0);
0955474b 94
b0a1714b 95 X509_set_subject_name(pCert, pName);
7c6e5bb8 96 X509_set_issuer_name(pCert, pName);
0955474b 97
3bbe5e7a 98 if (!X509_sign(pCert, pKey, EVP_sha1())) {
b0a1714b 99 X509_free(pCert);
100 EVP_PKEY_free(pKey);
0955474b 101 return;
102 }
103
b0a1714b 104 PEM_write_X509(pOut, pCert);
105 X509_free(pCert);
106 EVP_PKEY_free(pKey);
0955474b 107 }
0a622749 108}
7627ea11 109#endif /* HAVE_LIBSSL */
110
078bbcf0 111CString CUtils::GetIP(unsigned long addr) {
538d3ece 112 char szBuf[16];
113 memset((char*) szBuf, 0, 16);
114
115 if (addr >= (1 << 24)) {
116 unsigned long ip[4];
117 ip[0] = addr >> 24 & 255;
118 ip[1] = addr >> 16 & 255;
119 ip[2] = addr >> 8 & 255;
120 ip[3] = addr & 255;
121 sprintf(szBuf, "%lu.%lu.%lu.%lu", ip[0], ip[1], ip[2], ip[3]);
122 }
123
124 return szBuf;
125}
126
078bbcf0 127unsigned long CUtils::GetLongIP(const CString& sIP) {
4e6c6fea 128 unsigned long ret;
129 char ip[4][4];
f4618594 130 unsigned int i;
538d3ece 131
4e6c6fea 132 i = sscanf(sIP.c_str(), "%3[0-9].%3[0-9].%3[0-9].%3[0-9]",
133 ip[0], ip[1], ip[2], ip[3]);
134 if (i != 4)
538d3ece 135 return 0;
538d3ece 136
f4618594 137 // Beware that atoi("200") << 24 would overflow and turn negative!
138 ret = atol(ip[0]) << 24;
139 ret += atol(ip[1]) << 16;
140 ret += atol(ip[2]) << 8;
141 ret += atol(ip[3]) << 0;
4e6c6fea 142
143 return ret;
538d3ece 144}
145
cd63bae0 146// If you change this here and in GetSaltedHashPass(),
147// don't forget CUser::HASH_DEFAULT!
148const CString CUtils::sDefaultHash = "sha256";
1c2c5265 149CString CUtils::GetSaltedHashPass(CString& sSalt) {
150 sSalt = GetSalt();
bf2bd397 151
152 while (true) {
a3169af5 153 CString pass1 = CUtils::GetPass("Enter Password");
154 CString pass2 = CUtils::GetPass("Confirm Password");
155
156 if (!pass1.Equals(pass2, true)) {
bf2bd397 157 CUtils::PrintError("The supplied passwords did not match");
a3169af5 158 } else if (pass1.empty()) {
bf2bd397 159 CUtils::PrintError("You can not use an empty password");
160 } else {
161 // Construct the salted pass
cd63bae0 162 return SaltedSHA256Hash(pass1, sSalt);
bf2bd397 163 }
bf2bd397 164 }
bf2bd397 165}
166
1c2c5265 167CString CUtils::GetSalt() {
168 return CString::RandomString(20);
169}
170
cd63bae0 171CString CUtils::SaltedMD5Hash(const CString& sPass, const CString& sSalt) {
a3169af5 172 return CString(sPass + sSalt).MD5();
173}
174
cd63bae0 175CString CUtils::SaltedSHA256Hash(const CString& sPass, const CString& sSalt) {
176 return CString(sPass + sSalt).SHA256();
177}
178
7ab0b8d9 179CString CUtils::GetPass(const CString& sPrompt) {
1873745f 180 PrintPrompt(sPrompt);
2c6a54b6
PD
181#ifdef HAVE_GETPASSPHRASE
182 return getpassphrase("");
183#else
1873745f 184 return getpass("");
2c6a54b6 185#endif
1873745f 186}
187
078bbcf0 188bool CUtils::GetBoolInput(const CString& sPrompt, bool bDefault) {
c6eea2ae 189 return CUtils::GetBoolInput(sPrompt, &bDefault);
190}
191
078bbcf0 192bool CUtils::GetBoolInput(const CString& sPrompt, bool *pbDefault) {
193 CString sRet, sDefault;
c6eea2ae 194
195 if (pbDefault) {
196 sDefault = (*pbDefault) ? "yes" : "no";
197 }
198
88a993a6 199 while (true) {
200 GetInput(sPrompt, sRet, sDefault, "yes/no");
e233decc 201
88a993a6 202 if (sRet.Equals("y") || sRet.Equals("yes")) {
203 return true;
204 } else if (sRet.Equals("n") || sRet.Equals("no")) {
205 return false;
206 }
e233decc 207 }
e233decc 208}
209
078bbcf0 210bool CUtils::GetNumInput(const CString& sPrompt, unsigned int& uRet, unsigned int uMin, unsigned int uMax, unsigned int uDefault) {
3abf4222 211 if (uMin > uMax) {
212 return false;
213 }
214
a9e60b43 215 CString sDefault = (uDefault != (unsigned int) ~0) ? CString(uDefault) : "";
078bbcf0 216 CString sNum, sHint;
3abf4222 217
218 if (uMax != (unsigned int) ~0) {
a9e60b43 219 sHint = CString(uMin) + " to " + CString(uMax);
3abf4222 220 } else if (uMin > 0) {
a9e60b43 221 sHint = CString(uMin) + " and up";
3abf4222 222 }
223
224 while (true) {
225 GetInput(sPrompt, sNum, sDefault, sHint);
226 if (sNum.empty()) {
227 return false;
228 }
229
607a7f1c 230 uRet = sNum.ToUInt();
3abf4222 231
232 if ((uRet >= uMin && uRet <= uMax)) {
233 break;
234 }
235
236 CUtils::PrintError("Number must be " + sHint);
237 }
238
239 return true;
240}
241
078bbcf0 242bool CUtils::GetInput(const CString& sPrompt, CString& sRet, const CString& sDefault, const CString& sHint) {
243 CString sExtra;
ee620347 244 CString sInput;
3abf4222 245 sExtra += (!sHint.empty()) ? (" (" + sHint + ")") : "";
246 sExtra += (!sDefault.empty()) ? (" [" + sDefault + "]") : "";
247
c6eea2ae 248 PrintPrompt(sPrompt + sExtra);
e233decc 249 char szBuf[1024];
250 memset(szBuf, 0, 1024);
e3683f20 251 if (fgets(szBuf, 1024, stdin) == NULL) {
252 // Reading failed (Error? EOF?)
253 PrintError("Error while reading from stdin. Exiting...");
254 exit(-1);
255 }
ee620347 256 sInput = szBuf;
e233decc 257
ee620347 258 if (sInput.Right(1) == "\n") {
259 sInput.RightChomp();
e233decc 260 }
261
ee620347 262 if (sInput.empty()) {
c6eea2ae 263 sRet = sDefault;
ee620347 264 } else {
265 sRet = sInput;
c6eea2ae 266 }
267
e233decc 268 return !sRet.empty();
269}
270
078bbcf0 271void CUtils::PrintError(const CString& sMessage) {
ac5c021c 272 if (CDebug::StdoutIsTTY())
74fb58cc 273 fprintf(stdout, "\033[1m\033[34m[\033[31m ** \033[34m]\033[39m\033[22m %s\n", sMessage.c_str());
274 else
766d775f 275 fprintf(stdout, "%s\n", sMessage.c_str());
b665bd2b 276 fflush(stdout);
1873745f 277}
278
078bbcf0 279void CUtils::PrintPrompt(const CString& sMessage) {
ac5c021c 280 if (CDebug::StdoutIsTTY())
74fb58cc 281 fprintf(stdout, "\033[1m\033[34m[\033[33m ?? \033[34m]\033[39m\033[22m %s: ", sMessage.c_str());
282 else
283 fprintf(stdout, "[ ?? ] %s: ", sMessage.c_str());
b665bd2b 284 fflush(stdout);
a9d08422 285}
286
078bbcf0 287void CUtils::PrintMessage(const CString& sMessage, bool bStrong) {
ac5c021c 288 if (CDebug::StdoutIsTTY()) {
74fb58cc 289 if (bStrong)
290 fprintf(stdout, "\033[1m\033[34m[\033[33m ** \033[34m]\033[39m\033[22m \033[1m%s\033[22m\n",
291 sMessage.c_str());
292 else
293 fprintf(stdout, "\033[1m\033[34m[\033[33m ** \033[34m]\033[39m\033[22m %s\n",
294 sMessage.c_str());
295 } else
296 fprintf(stdout, "%s\n", sMessage.c_str());
b665bd2b 297
298 fflush(stdout);
a9d08422 299}
300
078bbcf0 301void CUtils::PrintAction(const CString& sMessage) {
ac5c021c 302 if (CDebug::StdoutIsTTY())
74fb58cc 303 fprintf(stdout, "\033[1m\033[34m[\033[32m \033[34m]\033[39m\033[22m %s... ", sMessage.c_str());
304 else
305 fprintf(stdout, "%s... ", sMessage.c_str());
a9d08422 306 fflush(stdout);
307}
308
078bbcf0 309void CUtils::PrintStatus(bool bSuccess, const CString& sMessage) {
ac5c021c 310 if (CDebug::StdoutIsTTY()) {
74fb58cc 311 if (!sMessage.empty()) {
312 if (bSuccess) {
313 fprintf(stdout, "%s", sMessage.c_str());
314 } else {
315 fprintf(stdout, "\033[1m\033[34m[\033[31m %s \033[34m]"
316 "\033[39m\033[22m", sMessage.c_str());
317 }
1873745f 318 }
a9d08422 319
74fb58cc 320 fprintf(stdout, "\r");
a9d08422 321
74fb58cc 322 if (bSuccess) {
323 fprintf(stdout, "\033[1m\033[34m[\033[32m ok \033[34m]\033[39m\033[22m\n");
324 } else {
325 fprintf(stdout, "\033[1m\033[34m[\033[31m !! \033[34m]\033[39m\033[22m\n");
326 }
a9d08422 327 } else {
74fb58cc 328 if (bSuccess) {
329 fprintf(stdout, "%s\n", sMessage.c_str());
330 } else {
331 if (!sMessage.empty()) {
332 fprintf(stdout, "[ %s ]", sMessage.c_str());
333 }
334
766d775f 335 fprintf(stdout, "\n");
74fb58cc 336 }
a9d08422 337 }
b665bd2b 338
339 fflush(stdout);
a9d08422 340}
341
078bbcf0 342bool CTable::AddColumn(const CString& sName) {
538d3ece 343 for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
5237a247 344 if (m_vsHeaders[a].Equals(sName)) {
538d3ece 345 return false;
346 }
347 }
348
349 m_vsHeaders.push_back(sName);
ec58e6f1 350 m_msuWidths[sName] = sName.size();
351
538d3ece 352 return true;
353}
354
355unsigned int CTable::AddRow() {
859c4ea1 356 // Don't add a row if no headers are defined
0b6c5cc1 357 if (m_vsHeaders.empty()) {
859c4ea1 358 return (unsigned int) -1;
359 }
360
c0c563de 361 // Add a vector with enough space for each column
362 push_back(vector<CString>(m_vsHeaders.size()));
859c4ea1 363 return size() - 1;
538d3ece 364}
365
078bbcf0 366bool CTable::SetCell(const CString& sColumn, const CString& sValue, unsigned int uRowIdx) {
538d3ece 367 if (uRowIdx == (unsigned int) ~0) {
368 if (!size()) {
369 return false;
370 }
371
372 uRowIdx = size() -1;
373 }
374
859c4ea1 375 unsigned int uColIdx = GetColumnIndex(sColumn);
376
377 if (uColIdx == (unsigned int) -1)
378 return false;
379
380 (*this)[uRowIdx][uColIdx] = sValue;
ec58e6f1 381
382 if (m_msuWidths[sColumn] < sValue.size())
383 m_msuWidths[sColumn] = sValue.size();
384
538d3ece 385 return true;
386}
387
ec58e6f1 388bool CTable::GetLine(unsigned int uIdx, CString& sLine) const {
538d3ece 389 stringstream ssRet;
390
2ccafaf5 391 if (empty()) {
538d3ece 392 return false;
393 }
394
395 if (uIdx == 1) {
538d3ece 396 ssRet.fill(' ');
397 ssRet << "| ";
398
399 for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
400 ssRet.width(GetColumnWidth(a));
401 ssRet << std::left << m_vsHeaders[a];
402 ssRet << ((a == m_vsHeaders.size() -1) ? " |" : " | ");
403 }
404
405 sLine = ssRet.str();
406 return true;
407 } else if ((uIdx == 0) || (uIdx == 2) || (uIdx == (size() +3))) {
408 ssRet.fill('-');
409 ssRet << "+-";
410
411 for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
412 ssRet.width(GetColumnWidth(a));
413 ssRet << std::left << "-";
414 ssRet << ((a == m_vsHeaders.size() -1) ? "-+" : "-+-");
415 }
416
417 sLine = ssRet.str();
418 return true;
419 } else {
420 uIdx -= 3;
421
422 if (uIdx < size()) {
c0c563de 423 const vector<CString>& mRow = (*this)[uIdx];
538d3ece 424 ssRet.fill(' ');
425 ssRet << "| ";
426
427 for (unsigned int c = 0; c < m_vsHeaders.size(); c++) {
428 ssRet.width(GetColumnWidth(c));
c0c563de 429 ssRet << std::left << mRow[c];
538d3ece 430 ssRet << ((c == m_vsHeaders.size() -1) ? " |" : " | ");
431 }
432
433 sLine = ssRet.str();
434 return true;
435 }
436 }
437
438 return false;
439}
440
c0c563de 441unsigned int CTable::GetColumnIndex(const CString& sName) const {
442 for (unsigned int i = 0; i < m_vsHeaders.size(); i++) {
443 if (m_vsHeaders[i] == sName)
444 return i;
445 }
446
235b10c2 447 DEBUG("CTable::GetColumnIndex(" + sName + ") failed");
03896135 448
859c4ea1 449 return (unsigned int) -1;
c0c563de 450}
451
ec58e6f1 452unsigned int CTable::GetColumnWidth(unsigned int uIdx) const {
538d3ece 453 if (uIdx >= m_vsHeaders.size()) {
454 return 0;
455 }
456
078bbcf0 457 const CString& sColName = m_vsHeaders[uIdx];
ec58e6f1 458 map<CString, unsigned int>::const_iterator it = m_msuWidths.find(sColName);
538d3ece 459
ec58e6f1 460 if (it == m_msuWidths.end()) {
461 // AddColumn() and SetCell() should make sure that we get a value :/
462 return 0;
538d3ece 463 }
ec58e6f1 464 return it->second;
538d3ece 465}
466
273d72c6 467void CTable::Clear() {
468 clear();
469 m_vsHeaders.clear();
470 m_msuWidths.clear();
471}
538d3ece 472
538d3ece 473#ifdef HAVE_LIBSSL
078bbcf0 474CBlowfish::CBlowfish(const CString & sPassword, int iEncrypt, const CString & sIvec) {
538d3ece 475 m_iEncrypt = iEncrypt;
476 m_ivec = (unsigned char *)calloc(sizeof(unsigned char), 8);
477 m_num = 0;
e233decc 478
538d3ece 479 if (sIvec.length() >= 8) {
480 memcpy(m_ivec, sIvec.data(), 8);
481 }
482
483 BF_set_key(&m_bkey, sPassword.length(), (unsigned char *)sPassword.data());
484}
485
486CBlowfish::~CBlowfish() {
487 free(m_ivec);
488}
489
490//! output must be freed
491unsigned char *CBlowfish::MD5(const unsigned char *input, u_int ilen) {
492 unsigned char *output = (unsigned char *)malloc(MD5_DIGEST_LENGTH);
493 ::MD5(input, ilen, output);
494 return output;
495}
496
078bbcf0 497//! returns an md5 of the CString (not hex encoded)
498CString CBlowfish::MD5(const CString & sInput, bool bHexEncode) {
499 CString sRet;
538d3ece 500 unsigned char *data = MD5((const unsigned char *)sInput.data(), sInput.length());
e233decc 501
538d3ece 502 if (!bHexEncode) {
503 sRet.append((const char *)data, MD5_DIGEST_LENGTH);
504 } else {
c64d7bc1 505 for (int a = 0; a < MD5_DIGEST_LENGTH; a++) {
538d3ece 506 sRet += g_HexDigits[data[a] >> 4];
507 sRet += g_HexDigits[data[a] & 0xf];
508 }
509 }
e233decc 510
538d3ece 511 free(data);
512 return sRet;
513}
514
515//! output must be the same size as input
516void CBlowfish::Crypt(unsigned char *input, unsigned char *output, u_int ibytes) {
517 BF_cfb64_encrypt(input, output, ibytes, &m_bkey, m_ivec, &m_num, m_iEncrypt);
518}
519
520//! must free result
521unsigned char * CBlowfish::Crypt(unsigned char *input, u_int ibytes) {
522 unsigned char *buff = (unsigned char *)malloc(ibytes);
523 Crypt(input, buff, ibytes);
524 return buff;
525}
e233decc 526
078bbcf0 527CString CBlowfish::Crypt(const CString & sData) {
538d3ece 528 unsigned char *buff = Crypt((unsigned char *)sData.data(), sData.length());
078bbcf0 529 CString sOutput;
538d3ece 530 sOutput.append((const char *)buff, sData.length());
531 free(buff);
532 return sOutput;
533}
534
535#endif // HAVE_LIBSSL