~ubuntu-branches/ubuntu/trusty/znc/trusty

« back to all changes in this revision

Viewing changes to Utils.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-05-06 09:18:27 UTC
  • mfrom: (21.1.5 experimental)
  • Revision ID: package-import@ubuntu.com-20130506091827-08sixjiyy3hjfx6b
Tags: 1.0-4
* Change section from znc-tcl to interpreters.
* Uploading to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2004-2011  See the AUTHORS file for details.
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
 
 */
8
 
 
9
 
#include "Utils.h"
10
 
#include "MD5.h"
11
 
#include "main.h"
12
 
#include "ZNCDebug.h"
13
 
#include <errno.h>
14
 
#ifdef HAVE_LIBSSL
15
 
#include <openssl/ssl.h>
16
 
#endif /* HAVE_LIBSSL */
17
 
#include <sstream>
18
 
#include <sys/stat.h>
19
 
#include <sys/types.h>
20
 
#include <unistd.h>
21
 
 
22
 
// Required with GCC 4.3+ if openssl is disabled
23
 
#include <cstring>
24
 
#include <cstdlib>
25
 
 
26
 
using std::stringstream;
27
 
 
28
 
CUtils::CUtils() {}
29
 
CUtils::~CUtils() {}
30
 
 
31
 
#ifdef HAVE_LIBSSL
32
 
void CUtils::GenerateCert(FILE *pOut, const CString& sHost) {
33
 
        EVP_PKEY *pKey = NULL;
34
 
        X509 *pCert = NULL;
35
 
        X509_NAME *pName = NULL;
36
 
        const int days = 365;
37
 
        const int years = 10;
38
 
 
39
 
        u_int iSeed = time(NULL);
40
 
        int serial = (rand_r(&iSeed) % 9999);
41
 
 
42
 
        RSA *pRSA = RSA_generate_key(2048, 0x10001, NULL, NULL);
43
 
        if ((pKey = EVP_PKEY_new())) {
44
 
                if (!EVP_PKEY_assign_RSA(pKey, pRSA)) {
45
 
                        EVP_PKEY_free(pKey);
46
 
                        return;
47
 
                }
48
 
 
49
 
                PEM_write_RSAPrivateKey(pOut, pRSA, NULL, NULL, 0, NULL, NULL);
50
 
 
51
 
                if (!(pCert = X509_new())) {
52
 
                        EVP_PKEY_free(pKey);
53
 
                        return;
54
 
                }
55
 
 
56
 
                X509_set_version(pCert, 2);
57
 
                ASN1_INTEGER_set(X509_get_serialNumber(pCert), serial);
58
 
                X509_gmtime_adj(X509_get_notBefore(pCert), 0);
59
 
                X509_gmtime_adj(X509_get_notAfter(pCert), (long)60*60*24*days*years);
60
 
                X509_set_pubkey(pCert, pKey);
61
 
 
62
 
                pName = X509_get_subject_name(pCert);
63
 
 
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
 
                }
74
 
 
75
 
                if (!pLogName) {
76
 
                        pLogName = "Unknown";
77
 
                }
78
 
 
79
 
                if (!pHostName) {
80
 
                        pHostName = "host.unknown";
81
 
                }
82
 
 
83
 
                CString sEmailAddr = pLogName;
84
 
                sEmailAddr += "@";
85
 
                sEmailAddr += pHostName;
86
 
 
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);
94
 
 
95
 
                X509_set_subject_name(pCert, pName);
96
 
                X509_set_issuer_name(pCert, pName);
97
 
 
98
 
                if (!X509_sign(pCert, pKey, EVP_sha1())) {
99
 
                        X509_free(pCert);
100
 
                        EVP_PKEY_free(pKey);
101
 
                        return;
102
 
                }
103
 
 
104
 
                PEM_write_X509(pOut, pCert);
105
 
                X509_free(pCert);
106
 
                EVP_PKEY_free(pKey);
107
 
        }
108
 
}
109
 
#endif /* HAVE_LIBSSL */
110
 
 
111
 
CString CUtils::GetIP(unsigned long addr) {
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
 
 
127
 
unsigned long CUtils::GetLongIP(const CString& sIP) {
128
 
        unsigned long ret;
129
 
        char ip[4][4];
130
 
        unsigned int i;
131
 
 
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)
135
 
                return 0;
136
 
 
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;
142
 
 
143
 
        return ret;
144
 
}
145
 
 
146
 
// If you change this here and in GetSaltedHashPass(),
147
 
// don't forget CUser::HASH_DEFAULT!
148
 
const CString CUtils::sDefaultHash = "sha256";
149
 
CString CUtils::GetSaltedHashPass(CString& sSalt) {
150
 
        sSalt = GetSalt();
151
 
 
152
 
        while (true) {
153
 
                CString pass1 = CUtils::GetPass("Enter Password");
154
 
                CString pass2 = CUtils::GetPass("Confirm Password");
155
 
 
156
 
                if (!pass1.Equals(pass2, true)) {
157
 
                        CUtils::PrintError("The supplied passwords did not match");
158
 
                } else if (pass1.empty()) {
159
 
                        CUtils::PrintError("You can not use an empty password");
160
 
                } else {
161
 
                        // Construct the salted pass
162
 
                        return SaltedSHA256Hash(pass1, sSalt);
163
 
                }
164
 
        }
165
 
}
166
 
 
167
 
CString CUtils::GetSalt() {
168
 
        return CString::RandomString(20);
169
 
}
170
 
 
171
 
CString CUtils::SaltedMD5Hash(const CString& sPass, const CString& sSalt) {
172
 
        return CString(sPass + sSalt).MD5();
173
 
}
174
 
 
175
 
CString CUtils::SaltedSHA256Hash(const CString& sPass, const CString& sSalt) {
176
 
        return CString(sPass + sSalt).SHA256();
177
 
}
178
 
 
179
 
CString CUtils::GetPass(const CString& sPrompt) {
180
 
        PrintPrompt(sPrompt);
181
 
#ifdef HAVE_GETPASSPHRASE
182
 
        return getpassphrase("");
183
 
#else
184
 
        return getpass("");
185
 
#endif
186
 
}
187
 
 
188
 
bool CUtils::GetBoolInput(const CString& sPrompt, bool bDefault) {
189
 
        return CUtils::GetBoolInput(sPrompt, &bDefault);
190
 
}
191
 
 
192
 
bool CUtils::GetBoolInput(const CString& sPrompt, bool *pbDefault) {
193
 
        CString sRet, sDefault;
194
 
 
195
 
        if (pbDefault) {
196
 
                sDefault = (*pbDefault) ? "yes" : "no";
197
 
        }
198
 
 
199
 
        while (true) {
200
 
                GetInput(sPrompt, sRet, sDefault, "yes/no");
201
 
 
202
 
                if (sRet.Equals("y") || sRet.Equals("yes")) {
203
 
                        return true;
204
 
                } else if (sRet.Equals("n") || sRet.Equals("no")) {
205
 
                        return false;
206
 
                }
207
 
        }
208
 
}
209
 
 
210
 
bool CUtils::GetNumInput(const CString& sPrompt, unsigned int& uRet, unsigned int uMin, unsigned int uMax, unsigned int uDefault) {
211
 
        if (uMin > uMax) {
212
 
                return false;
213
 
        }
214
 
 
215
 
        CString sDefault = (uDefault != (unsigned int) ~0) ? CString(uDefault) : "";
216
 
        CString sNum, sHint;
217
 
 
218
 
        if (uMax != (unsigned int) ~0) {
219
 
                sHint = CString(uMin) + " to " + CString(uMax);
220
 
        } else if (uMin > 0) {
221
 
                sHint = CString(uMin) + " and up";
222
 
        }
223
 
 
224
 
        while (true) {
225
 
                GetInput(sPrompt, sNum, sDefault, sHint);
226
 
                if (sNum.empty()) {
227
 
                        return false;
228
 
                }
229
 
 
230
 
                uRet = sNum.ToUInt();
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
 
 
242
 
bool CUtils::GetInput(const CString& sPrompt, CString& sRet, const CString& sDefault, const CString& sHint) {
243
 
        CString sExtra;
244
 
        CString sInput;
245
 
        sExtra += (!sHint.empty()) ? (" (" + sHint + ")") : "";
246
 
        sExtra += (!sDefault.empty()) ? (" [" + sDefault + "]") : "";
247
 
 
248
 
        PrintPrompt(sPrompt + sExtra);
249
 
        char szBuf[1024];
250
 
        memset(szBuf, 0, 1024);
251
 
        if (fgets(szBuf, 1024, stdin) == NULL) {
252
 
                // Reading failed (Error? EOF?)
253
 
                PrintError("Error while reading from stdin. Exiting...");
254
 
                exit(-1);
255
 
        }
256
 
        sInput = szBuf;
257
 
 
258
 
        if (sInput.Right(1) == "\n") {
259
 
                sInput.RightChomp();
260
 
        }
261
 
 
262
 
        if (sInput.empty()) {
263
 
                sRet = sDefault;
264
 
        } else {
265
 
                sRet = sInput;
266
 
        }
267
 
 
268
 
        return !sRet.empty();
269
 
}
270
 
 
271
 
void CUtils::PrintError(const CString& sMessage) {
272
 
        if (CDebug::StdoutIsTTY())
273
 
                fprintf(stdout, "\033[1m\033[34m[\033[31m ** \033[34m]\033[39m\033[22m %s\n", sMessage.c_str());
274
 
        else
275
 
                fprintf(stdout, "%s\n", sMessage.c_str());
276
 
        fflush(stdout);
277
 
}
278
 
 
279
 
void CUtils::PrintPrompt(const CString& sMessage) {
280
 
        if (CDebug::StdoutIsTTY())
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());
284
 
        fflush(stdout);
285
 
}
286
 
 
287
 
void CUtils::PrintMessage(const CString& sMessage, bool bStrong) {
288
 
        if (CDebug::StdoutIsTTY()) {
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());
297
 
 
298
 
        fflush(stdout);
299
 
}
300
 
 
301
 
void CUtils::PrintAction(const CString& sMessage) {
302
 
        if (CDebug::StdoutIsTTY())
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());
306
 
        fflush(stdout);
307
 
}
308
 
 
309
 
void CUtils::PrintStatus(bool bSuccess, const CString& sMessage) {
310
 
        if (CDebug::StdoutIsTTY()) {
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
 
                        }
318
 
                }
319
 
 
320
 
                fprintf(stdout, "\r");
321
 
 
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
 
                }
327
 
        } else {
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
 
 
335
 
                        fprintf(stdout, "\n");
336
 
                }
337
 
        }
338
 
 
339
 
        fflush(stdout);
340
 
}
341
 
 
342
 
bool CTable::AddColumn(const CString& sName) {
343
 
        for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
344
 
                if (m_vsHeaders[a].Equals(sName)) {
345
 
                        return false;
346
 
                }
347
 
        }
348
 
 
349
 
        m_vsHeaders.push_back(sName);
350
 
        m_msuWidths[sName] = sName.size();
351
 
 
352
 
        return true;
353
 
}
354
 
 
355
 
unsigned int CTable::AddRow() {
356
 
        // Don't add a row if no headers are defined
357
 
        if (m_vsHeaders.empty()) {
358
 
                return (unsigned int) -1;
359
 
        }
360
 
 
361
 
        // Add a vector with enough space for each column
362
 
        push_back(vector<CString>(m_vsHeaders.size()));
363
 
        return size() - 1;
364
 
}
365
 
 
366
 
bool CTable::SetCell(const CString& sColumn, const CString& sValue, unsigned int uRowIdx) {
367
 
        if (uRowIdx == (unsigned int) ~0) {
368
 
                if (!size()) {
369
 
                        return false;
370
 
                }
371
 
 
372
 
                uRowIdx = size() -1;
373
 
        }
374
 
 
375
 
        unsigned int uColIdx = GetColumnIndex(sColumn);
376
 
 
377
 
        if (uColIdx == (unsigned int) -1)
378
 
                return false;
379
 
 
380
 
        (*this)[uRowIdx][uColIdx] = sValue;
381
 
 
382
 
        if (m_msuWidths[sColumn] < sValue.size())
383
 
                m_msuWidths[sColumn] = sValue.size();
384
 
 
385
 
        return true;
386
 
}
387
 
 
388
 
bool CTable::GetLine(unsigned int uIdx, CString& sLine) const {
389
 
        stringstream ssRet;
390
 
 
391
 
        if (empty()) {
392
 
                return false;
393
 
        }
394
 
 
395
 
        if (uIdx == 1) {
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()) {
423
 
                        const vector<CString>& mRow = (*this)[uIdx];
424
 
                        ssRet.fill(' ');
425
 
                        ssRet << "| ";
426
 
 
427
 
                        for (unsigned int c = 0; c < m_vsHeaders.size(); c++) {
428
 
                                ssRet.width(GetColumnWidth(c));
429
 
                                ssRet << std::left << mRow[c];
430
 
                                ssRet << ((c == m_vsHeaders.size() -1) ? " |" : " | ");
431
 
                        }
432
 
 
433
 
                        sLine = ssRet.str();
434
 
                        return true;
435
 
                }
436
 
        }
437
 
 
438
 
        return false;
439
 
}
440
 
 
441
 
unsigned 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
 
 
447
 
        DEBUG("CTable::GetColumnIndex(" + sName + ") failed");
448
 
 
449
 
        return (unsigned int) -1;
450
 
}
451
 
 
452
 
unsigned int CTable::GetColumnWidth(unsigned int uIdx) const {
453
 
        if (uIdx >= m_vsHeaders.size()) {
454
 
                return 0;
455
 
        }
456
 
 
457
 
        const CString& sColName = m_vsHeaders[uIdx];
458
 
        map<CString, unsigned int>::const_iterator it = m_msuWidths.find(sColName);
459
 
 
460
 
        if (it == m_msuWidths.end()) {
461
 
                // AddColumn() and SetCell() should make sure that we get a value :/
462
 
                return 0;
463
 
        }
464
 
        return it->second;
465
 
}
466
 
 
467
 
void CTable::Clear() {
468
 
        clear();
469
 
        m_vsHeaders.clear();
470
 
        m_msuWidths.clear();
471
 
}
472
 
 
473
 
#ifdef HAVE_LIBSSL
474
 
CBlowfish::CBlowfish(const CString & sPassword, int iEncrypt, const CString & sIvec) {
475
 
        m_iEncrypt = iEncrypt;
476
 
        m_ivec = (unsigned char *)calloc(sizeof(unsigned char), 8);
477
 
        m_num = 0;
478
 
 
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
 
 
486
 
CBlowfish::~CBlowfish() {
487
 
        free(m_ivec);
488
 
}
489
 
 
490
 
//! output must be freed
491
 
unsigned 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
 
 
497
 
//! returns an md5 of the CString (not hex encoded)
498
 
CString CBlowfish::MD5(const CString & sInput, bool bHexEncode) {
499
 
        CString sRet;
500
 
        unsigned char *data = MD5((const unsigned char *)sInput.data(), sInput.length());
501
 
 
502
 
        if (!bHexEncode) {
503
 
                sRet.append((const char *)data, MD5_DIGEST_LENGTH);
504
 
        } else {
505
 
                for (int a = 0; a < MD5_DIGEST_LENGTH; a++) {
506
 
                        sRet += g_HexDigits[data[a] >> 4];
507
 
                        sRet += g_HexDigits[data[a] & 0xf];
508
 
                }
509
 
        }
510
 
 
511
 
        free(data);
512
 
        return sRet;
513
 
}
514
 
 
515
 
//! output must be the same size as input
516
 
void 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
521
 
unsigned 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
 
}
526
 
 
527
 
CString CBlowfish::Crypt(const CString & sData) {
528
 
        unsigned char *buff = Crypt((unsigned char *)sData.data(), sData.length());
529
 
        CString sOutput;
530
 
        sOutput.append((const char *)buff, sData.length());
531
 
        free(buff);
532
 
        return sOutput;
533
 
}
534
 
 
535
 
#endif // HAVE_LIBSSL