| 1231 |
return result; |
return result; |
| 1232 |
} |
} |
| 1233 |
|
|
| 1234 |
|
static char FAR *format_specified_host_key(Key *key, char *hostname, unsigned short tcpport) |
| 1235 |
|
{ |
| 1236 |
|
int host_len = strlen(hostname); |
| 1237 |
|
char *result = NULL; |
| 1238 |
|
int index; |
| 1239 |
|
ssh_keytype type = key->type; |
| 1240 |
|
|
| 1241 |
|
switch (type) { |
| 1242 |
|
case KEY_RSA1: |
| 1243 |
|
{ |
| 1244 |
|
int result_len = host_len + 50 + 8 + |
| 1245 |
|
get_ushort16_MSBfirst(key->exp) / 3 + |
| 1246 |
|
get_ushort16_MSBfirst(key->mod) / 3; |
| 1247 |
|
result = (char FAR *) malloc(result_len); |
| 1248 |
|
|
| 1249 |
|
if (tcpport == 22) { |
| 1250 |
|
strncpy_s(result, result_len, hostname, _TRUNCATE); |
| 1251 |
|
index = host_len; |
| 1252 |
|
} |
| 1253 |
|
else { |
| 1254 |
|
_snprintf_s(result, result_len, _TRUNCATE, "[%s]:%d", |
| 1255 |
|
hostname, |
| 1256 |
|
tcpport); |
| 1257 |
|
index = strlen(result); |
| 1258 |
|
} |
| 1259 |
|
|
| 1260 |
|
_snprintf_s(result + index, result_len - host_len, _TRUNCATE, |
| 1261 |
|
" %d ", key->bits); |
| 1262 |
|
index += strlen(result + index); |
| 1263 |
|
index += print_mp_int(result + index, key->exp); |
| 1264 |
|
result[index] = ' '; |
| 1265 |
|
index++; |
| 1266 |
|
index += print_mp_int(result + index, key->mod); |
| 1267 |
|
strncpy_s(result + index, result_len - index, " \r\n", _TRUNCATE); |
| 1268 |
|
|
| 1269 |
|
break; |
| 1270 |
|
} |
| 1271 |
|
|
| 1272 |
|
case KEY_RSA: |
| 1273 |
|
case KEY_DSA: |
| 1274 |
|
case KEY_ECDSA256: |
| 1275 |
|
case KEY_ECDSA384: |
| 1276 |
|
case KEY_ECDSA521: |
| 1277 |
|
case KEY_ED25519: |
| 1278 |
|
{ |
| 1279 |
|
//Key *key = &pvar->hosts_state.hostkey; |
| 1280 |
|
char *blob = NULL; |
| 1281 |
|
int blen, uulen, msize; |
| 1282 |
|
char *uu = NULL; |
| 1283 |
|
int n; |
| 1284 |
|
|
| 1285 |
|
key_to_blob(key, &blob, &blen); |
| 1286 |
|
uulen = 2 * blen; |
| 1287 |
|
uu = malloc(uulen); |
| 1288 |
|
if (uu == NULL) { |
| 1289 |
|
goto error; |
| 1290 |
|
} |
| 1291 |
|
n = uuencode(blob, blen, uu, uulen); |
| 1292 |
|
if (n > 0) { |
| 1293 |
|
msize = host_len + 50 + uulen; |
| 1294 |
|
result = malloc(msize); |
| 1295 |
|
if (result == NULL) { |
| 1296 |
|
goto error; |
| 1297 |
|
} |
| 1298 |
|
|
| 1299 |
|
// setup |
| 1300 |
|
if (tcpport == 22) { |
| 1301 |
|
_snprintf_s(result, msize, _TRUNCATE, "%s %s %s\r\n", |
| 1302 |
|
hostname, |
| 1303 |
|
get_sshname_from_key(key), |
| 1304 |
|
uu); |
| 1305 |
|
} |
| 1306 |
|
else { |
| 1307 |
|
_snprintf_s(result, msize, _TRUNCATE, "[%s]:%d %s %s\r\n", |
| 1308 |
|
hostname, |
| 1309 |
|
tcpport, |
| 1310 |
|
get_sshname_from_key(key), |
| 1311 |
|
uu); |
| 1312 |
|
} |
| 1313 |
|
} |
| 1314 |
|
error: |
| 1315 |
|
if (blob != NULL) |
| 1316 |
|
free(blob); |
| 1317 |
|
if (uu != NULL) |
| 1318 |
|
free(uu); |
| 1319 |
|
|
| 1320 |
|
break; |
| 1321 |
|
} |
| 1322 |
|
|
| 1323 |
|
default: |
| 1324 |
|
return NULL; |
| 1325 |
|
|
| 1326 |
|
} |
| 1327 |
|
|
| 1328 |
|
return result; |
| 1329 |
|
} |
| 1330 |
|
|
| 1331 |
static void add_host_key(PTInstVar pvar) |
static void add_host_key(PTInstVar pvar) |
| 1332 |
{ |
{ |
| 1333 |
char FAR *name = NULL; |
char FAR *name = NULL; |
| 1380 |
} |
} |
| 1381 |
} |
} |
| 1382 |
|
|
| 1383 |
|
// 指定したキーを known_hosts に追加する。 |
| 1384 |
|
void HOSTS_add_host_key(PTInstVar pvar, Key *key) |
| 1385 |
|
{ |
| 1386 |
|
char FAR *name = NULL; |
| 1387 |
|
char *hostname; |
| 1388 |
|
unsigned short tcpport; |
| 1389 |
|
|
| 1390 |
|
hostname = pvar->ssh_state.hostname; |
| 1391 |
|
tcpport = pvar->ssh_state.tcpport; |
| 1392 |
|
|
| 1393 |
|
if (pvar->hosts_state.file_names != NULL) |
| 1394 |
|
name = pvar->hosts_state.file_names[0]; |
| 1395 |
|
|
| 1396 |
|
if (name == NULL || name[0] == 0) { |
| 1397 |
|
UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar, |
| 1398 |
|
"The host and its key cannot be added, because no known-hosts file has been specified.\n" |
| 1399 |
|
"Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box."); |
| 1400 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1401 |
|
} |
| 1402 |
|
else { |
| 1403 |
|
char FAR *keydata = format_specified_host_key(key, hostname, tcpport); |
| 1404 |
|
int length = strlen(keydata); |
| 1405 |
|
int fd; |
| 1406 |
|
int amount_written; |
| 1407 |
|
int close_result; |
| 1408 |
|
char buf[FILENAME_MAX]; |
| 1409 |
|
|
| 1410 |
|
get_teraterm_dir_relative_name(buf, sizeof(buf), name); |
| 1411 |
|
fd = _open(buf, |
| 1412 |
|
_O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY, |
| 1413 |
|
_S_IREAD | _S_IWRITE); |
| 1414 |
|
if (fd == -1) { |
| 1415 |
|
if (errno == EACCES) { |
| 1416 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar, |
| 1417 |
|
"An error occurred while trying to write the host key.\n" |
| 1418 |
|
"You do not have permission to write to the known-hosts file."); |
| 1419 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1420 |
|
} |
| 1421 |
|
else { |
| 1422 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar, |
| 1423 |
|
"An error occurred while trying to write the host key.\n" |
| 1424 |
|
"The host key could not be written."); |
| 1425 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1426 |
|
} |
| 1427 |
|
return; |
| 1428 |
|
} |
| 1429 |
|
|
| 1430 |
|
amount_written = _write(fd, keydata, length); |
| 1431 |
|
free(keydata); |
| 1432 |
|
close_result = _close(fd); |
| 1433 |
|
|
| 1434 |
|
if (amount_written != length || close_result == -1) { |
| 1435 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar, |
| 1436 |
|
"An error occurred while trying to write the host key.\n" |
| 1437 |
|
"The host key could not be written."); |
| 1438 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1439 |
|
} |
| 1440 |
|
} |
| 1441 |
|
} |
| 1442 |
|
|
| 1443 |
static char FAR *copy_mp_int(char FAR * num) |
static char FAR *copy_mp_int(char FAR * num) |
| 1444 |
{ |
{ |
| 1445 |
int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2; |
int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2; |
| 1670 |
} |
} |
| 1671 |
} |
} |
| 1672 |
|
|
| 1673 |
|
|
| 1674 |
|
void HOSTS_delete_all_hostkeys(PTInstVar pvar) |
| 1675 |
|
{ |
| 1676 |
|
char FAR *name = pvar->hosts_state.file_names[0]; |
| 1677 |
|
char *hostname; |
| 1678 |
|
unsigned short tcpport; |
| 1679 |
|
|
| 1680 |
|
hostname = pvar->ssh_state.hostname; |
| 1681 |
|
tcpport = pvar->ssh_state.tcpport; |
| 1682 |
|
|
| 1683 |
|
if (name == NULL || name[0] == 0) { |
| 1684 |
|
UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar, |
| 1685 |
|
"The host and its key cannot be added, because no known-hosts file has been specified.\n" |
| 1686 |
|
"Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box."); |
| 1687 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1688 |
|
} |
| 1689 |
|
else { |
| 1690 |
|
Key key; // 接続中のホストのキー |
| 1691 |
|
Key *key_freed; |
| 1692 |
|
int length; |
| 1693 |
|
char filename[MAX_PATH]; |
| 1694 |
|
char tmp[L_tmpnam]; |
| 1695 |
|
int fd; |
| 1696 |
|
int amount_written = 0; |
| 1697 |
|
int close_result; |
| 1698 |
|
int data_index = 0; |
| 1699 |
|
char buf[FILENAME_MAX]; |
| 1700 |
|
|
| 1701 |
|
// 書き込み一時ファイルを開く |
| 1702 |
|
_getcwd(filename, sizeof(filename)); |
| 1703 |
|
tmpnam_s(tmp, sizeof(tmp)); |
| 1704 |
|
strcat_s(filename, sizeof(filename), tmp); |
| 1705 |
|
fd = _open(filename, |
| 1706 |
|
_O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC, |
| 1707 |
|
_S_IREAD | _S_IWRITE); |
| 1708 |
|
|
| 1709 |
|
if (fd == -1) { |
| 1710 |
|
if (errno == EACCES) { |
| 1711 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar, |
| 1712 |
|
"An error occurred while trying to write the host key.\n" |
| 1713 |
|
"You do not have permission to write to the known-hosts file."); |
| 1714 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1715 |
|
} |
| 1716 |
|
else { |
| 1717 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar, |
| 1718 |
|
"An error occurred while trying to write the host key.\n" |
| 1719 |
|
"The host key could not be written."); |
| 1720 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1721 |
|
} |
| 1722 |
|
return; |
| 1723 |
|
} |
| 1724 |
|
|
| 1725 |
|
// 接続中のサーバのキーを読み込む |
| 1726 |
|
memset(&key, 0, sizeof(key)); |
| 1727 |
|
switch (pvar->hosts_state.hostkey.type) { |
| 1728 |
|
case KEY_RSA1: // SSH1 |
| 1729 |
|
key.type = KEY_RSA1; |
| 1730 |
|
key.bits = pvar->hosts_state.hostkey.bits; |
| 1731 |
|
key.exp = copy_mp_int(pvar->hosts_state.hostkey.exp); |
| 1732 |
|
key.mod = copy_mp_int(pvar->hosts_state.hostkey.mod); |
| 1733 |
|
break; |
| 1734 |
|
case KEY_RSA: // SSH2 RSA |
| 1735 |
|
key.type = KEY_RSA; |
| 1736 |
|
key.rsa = duplicate_RSA(pvar->hosts_state.hostkey.rsa); |
| 1737 |
|
break; |
| 1738 |
|
case KEY_DSA: // SSH2 DSA |
| 1739 |
|
key.type = KEY_DSA; |
| 1740 |
|
key.dsa = duplicate_DSA(pvar->hosts_state.hostkey.dsa); |
| 1741 |
|
break; |
| 1742 |
|
case KEY_ECDSA256: |
| 1743 |
|
case KEY_ECDSA384: |
| 1744 |
|
case KEY_ECDSA521: |
| 1745 |
|
key.type = pvar->hosts_state.hostkey.type; |
| 1746 |
|
key.ecdsa = EC_KEY_dup(pvar->hosts_state.hostkey.ecdsa); |
| 1747 |
|
break; |
| 1748 |
|
case KEY_ED25519: |
| 1749 |
|
key.type = pvar->hosts_state.hostkey.type; |
| 1750 |
|
key.ed25519_pk = duplicate_ED25519_PK(pvar->hosts_state.hostkey.ed25519_pk); |
| 1751 |
|
break; |
| 1752 |
|
} |
| 1753 |
|
|
| 1754 |
|
// ファイルから読み込む |
| 1755 |
|
begin_read_host_files(pvar, 0); |
| 1756 |
|
do { |
| 1757 |
|
int host_index = 0; |
| 1758 |
|
int matched = 0; |
| 1759 |
|
int keybits = 0; |
| 1760 |
|
char FAR *data; |
| 1761 |
|
int do_write = 0; |
| 1762 |
|
length = amount_written = 0; |
| 1763 |
|
|
| 1764 |
|
if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1)) { |
| 1765 |
|
break; |
| 1766 |
|
} |
| 1767 |
|
|
| 1768 |
|
if (data_index == pvar->hosts_state.file_data_index) { |
| 1769 |
|
// index が進まない == 最後まで読んだ |
| 1770 |
|
break; |
| 1771 |
|
} |
| 1772 |
|
|
| 1773 |
|
data = pvar->hosts_state.file_data + data_index; |
| 1774 |
|
host_index = eat_spaces(data); |
| 1775 |
|
|
| 1776 |
|
if (data[host_index] == '#') { |
| 1777 |
|
do_write = 1; |
| 1778 |
|
} |
| 1779 |
|
else { |
| 1780 |
|
// ホストの照合 |
| 1781 |
|
host_index--; |
| 1782 |
|
do { |
| 1783 |
|
int negated; |
| 1784 |
|
int bracketed; |
| 1785 |
|
char *end_bracket; |
| 1786 |
|
int host_matched = 0; |
| 1787 |
|
unsigned short keyfile_port = 22; |
| 1788 |
|
|
| 1789 |
|
host_index++; |
| 1790 |
|
negated = data[host_index] == '!'; |
| 1791 |
|
|
| 1792 |
|
if (negated) { |
| 1793 |
|
host_index++; |
| 1794 |
|
bracketed = data[host_index] == '['; |
| 1795 |
|
if (bracketed) { |
| 1796 |
|
end_bracket = strstr(data + host_index + 1, "]:"); |
| 1797 |
|
if (end_bracket != NULL) { |
| 1798 |
|
*end_bracket = ' '; |
| 1799 |
|
host_index++; |
| 1800 |
|
} |
| 1801 |
|
} |
| 1802 |
|
host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname); |
| 1803 |
|
if (bracketed && end_bracket != NULL) { |
| 1804 |
|
*end_bracket = ']'; |
| 1805 |
|
keyfile_port = atoi(end_bracket + 2); |
| 1806 |
|
} |
| 1807 |
|
if (host_matched && keyfile_port == pvar->ssh_state.tcpport) { |
| 1808 |
|
matched = 0; |
| 1809 |
|
// 接続バージョンチェックのために host_index を進めてから抜ける |
| 1810 |
|
host_index--; |
| 1811 |
|
do { |
| 1812 |
|
host_index++; |
| 1813 |
|
host_index += eat_to_end_of_pattern(data + host_index); |
| 1814 |
|
} while (data[host_index] == ','); |
| 1815 |
|
break; |
| 1816 |
|
} |
| 1817 |
|
} |
| 1818 |
|
else { |
| 1819 |
|
bracketed = data[host_index] == '['; |
| 1820 |
|
if (bracketed) { |
| 1821 |
|
end_bracket = strstr(data + host_index + 1, "]:"); |
| 1822 |
|
if (end_bracket != NULL) { |
| 1823 |
|
*end_bracket = ' '; |
| 1824 |
|
host_index++; |
| 1825 |
|
} |
| 1826 |
|
} |
| 1827 |
|
host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname); |
| 1828 |
|
if (bracketed && end_bracket != NULL) { |
| 1829 |
|
*end_bracket = ']'; |
| 1830 |
|
keyfile_port = atoi(end_bracket + 2); |
| 1831 |
|
} |
| 1832 |
|
if (host_matched && keyfile_port == pvar->ssh_state.tcpport) { |
| 1833 |
|
matched = 1; |
| 1834 |
|
} |
| 1835 |
|
} |
| 1836 |
|
host_index += eat_to_end_of_pattern(data + host_index); |
| 1837 |
|
} while (data[host_index] == ','); |
| 1838 |
|
|
| 1839 |
|
// ホストが等しくない |
| 1840 |
|
if (!matched) { |
| 1841 |
|
do_write = 1; |
| 1842 |
|
} |
| 1843 |
|
// ホストが等しい |
| 1844 |
|
else { |
| 1845 |
|
// 一切書き込みをしない。 |
| 1846 |
|
|
| 1847 |
|
} |
| 1848 |
|
} |
| 1849 |
|
|
| 1850 |
|
// 書き込み処理 |
| 1851 |
|
if (do_write) { |
| 1852 |
|
length = pvar->hosts_state.file_data_index - data_index; |
| 1853 |
|
amount_written = |
| 1854 |
|
_write(fd, pvar->hosts_state.file_data + data_index, |
| 1855 |
|
length); |
| 1856 |
|
|
| 1857 |
|
if (amount_written != length) { |
| 1858 |
|
goto error1; |
| 1859 |
|
} |
| 1860 |
|
} |
| 1861 |
|
data_index = pvar->hosts_state.file_data_index; |
| 1862 |
|
} while (1); // 最後まで読む |
| 1863 |
|
|
| 1864 |
|
error1: |
| 1865 |
|
close_result = _close(fd); |
| 1866 |
|
if (amount_written != length || close_result == -1) { |
| 1867 |
|
UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar, |
| 1868 |
|
"An error occurred while trying to write the host key.\n" |
| 1869 |
|
"The host key could not be written."); |
| 1870 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 1871 |
|
goto error2; |
| 1872 |
|
} |
| 1873 |
|
|
| 1874 |
|
// 書き込み一時ファイルからリネーム |
| 1875 |
|
get_teraterm_dir_relative_name(buf, sizeof(buf), name); |
| 1876 |
|
_unlink(buf); |
| 1877 |
|
rename(filename, buf); |
| 1878 |
|
|
| 1879 |
|
error2: |
| 1880 |
|
_unlink(filename); |
| 1881 |
|
|
| 1882 |
|
finish_read_host_files(pvar, 0); |
| 1883 |
|
|
| 1884 |
|
// 最後にメモリを解放しておく。 |
| 1885 |
|
key_freed = key_new(KEY_UNSPEC); |
| 1886 |
|
memcpy(key_freed, &key, sizeof(Key)); |
| 1887 |
|
key_free(key_freed); |
| 1888 |
|
} |
| 1889 |
|
} |
| 1890 |
|
|
| 1891 |
|
|
| 1892 |
// |
// |
| 1893 |
// Unknown hostのホスト公開鍵を known_hosts ファイルへ保存するかどうかを |
// Unknown hostのホスト公開鍵を known_hosts ファイルへ保存するかどうかを |
| 1894 |
// ユーザに確認させる。 |
// ユーザに確認させる。 |