Posts

C 标准函数库

0x00 序

ANSI C 库分为不同的组,每个组都具有与之相关的头文件。这里列出了头文件并简单地描述了相关的函数。

0x01 诊断 assert.h

这个头文件把 assert() 定义为一个宏。包含在 assert.h 头文件之前定义宏标识符 NDEBUG 可以禁用 assert() 宏。用作参数的表达式通常是一个关系或逻辑表达式,如果程序正确执行的话,那么在程序执行到该点时表达式应该为真。

表 1.1 诊断宏
原型 说明
voidassert (int exprs) 如果 exprs 为非 0 (或真),宏不做任何事; 如果 exprs 为 0 (假),assert() 就显示该表达式、assert() 语句所在的行号和包含该语句的文件名;然后它调用 abort()

0x02 复数 complex.h(C99)

C99 添加了对复数计算的广泛支持。除了提供 _Complex 类型之外,实现还可以提供 _Imaginary 类型。该文件定义了表 1.2 中列出的宏。

表 2.1 complex.h 宏
说明
complex 展开为类型关键字 _Complex
_Complex_I 展开为一个类型是 const float _Complex 的表达式,它的值平方后为 -1
imaginary 如果支持虚数类型,就展开为类型关键字 _Imaginary
_Imaginary_I 展开为一个类型是 const float _Imaginary 的表达式,它的值平方后为 -1
I 展开为 _Complex_I 或 _Imaginary_I

在 C 中使用 complex.h 头文件实现对复数的支持,而在 C++ 中是使用 complex 头文件实现。两种实现由很大的不同,C++ 是用类来定义复数类型的。 可以使用 STDC CX_LIMITED_RANGE 编译指示来表明是可以使用普通的数学公式(打开时),还是要对极值进行特别的注意(关闭时):

#include <complex.h>
#pragma STDC CX_LIMITED_RANGE on

库函数可以分为三种: double、float 和 long double。表 2.2 列出了 double 版本。float 和 long double 版本只是在函数名后面分别加上 f 和 l。这样,csinf() 就是 csin() 的 float 版本,而 csinl() 是 csin() 的 long double 版本。 角度是以弧度为单位的。

表 2.2 复数函数
原型 说明
double complex cacos (double complex z); 返回 z 的复数反余弦
double complex casis (double complex z); 返回 z 的复数反正弦
double complex catan (double complex z); 返回 z 的复数反正切
double complex ccos (double complex z); 返回 z 的复数余弦
double complex csin (double complex z); 返回 z 的复数正弦
double complex ctan (double complex z); 返回 z 的复数正切
double complex cacosh (double complex z); 返回 z 的复数反双曲余弦
double complex casish (double complex z); 返回 z 的复数反双曲正弦
double complex catanh (double complex z); 返回 z 的复数反双曲正切
double complex ccosh (double complex z); 返回 z 的复数双曲余弦
double complex csinh (double complex z); 返回 z 的复数双曲正弦
double complex ctanh (double complex z); 返回 z 的复数双曲正切
double complex cexp (double complex z); 返回 e 的 z 次幂的复数值
double complex clog (double complex z); 返回 z 的自然对数(以 e 为底)的复数值
double cabs (double complex z); 返回 z 的绝对值(或长度)
double complex cpows (double complex z, double complex y); 返回 z 的 y 次幂的值
double complex csqrt (double complex z); 返回 z 复数平方根
double carg (double complex z); 以弧度返回 z 的相位角(或辐角)
double cimag (double complex z); 以实数形式返回 z 的虚部
double complex conj (double complex z); 返回 z 的共轭复数
double complex cproj (double complex z); 返回 z 在 Riemann 域上的投影
double creal (double complex z); 以实数形式返回 z 的实部

0x02 字符处理 ctype.h

这些函数接受 int 参数,这些参数能够被表示为 unsigned char 值或 EOF,如果提供其他值则没有定义。在表 3.1 中「真」作为「非 0 值」的速记形式。对一些定义的解释要依赖于当前场所的设置,它是由 locale.h 中的函数来控制的;该表显示了在「C」场所中的解释。

表 3.1 字符处理函数
原型 说明
int isalnum (int c); 如果 c 是字母数字(字母或数字)则返回真
int isalpha (int c); 如果 c 是字母则返回真
int isblank (int c); 如果 c 是空格或水平制表符则返回真(C99)
int iscntrl (int c); 如果 c 是控制字符,例如 Ctrl+B 则返回真
int isdigit (int c); 如果 c 是数字则返回真
int isgraph (int c); 如果 c 是空格外的任何打印字符则返回真
int islower (int c); 如果 c 是小写字符则返回真
int isprint (int c); 如果 c 是打印字符则返回真
int ispunct (int c); 如果 c 是标点字符(除空格或字母数字之外的任何打印字符)则返回真
int isspace (int c); 如果 c 是下列空白字符:空格、换行、走纸、回车、垂直制表、水平制表或其他由实现定义的字符,则返回真
int isupper (int c); 如果 c 是大写字符则返回真
int isxdigit (int c); 如果 c 是十六进制数字字符则返回真
int tolower (int c); 如果参数为大写字符则返回它的小写,否则返回原始参数
int toupper (int c); 如果参数为小写字符则返回它的小写,否则返回原始参数

初始化 CentOS 7 以及安全设置

0x01 root 登陆

首先,登陆服务器。以下以「SSH」为例,如下代码所示,在 「Terminal」 或者命令行中输入 ssh 命令。

ssh USER_NAME@SERVER_IP_ADDRESS
  • ssh: Bash 中的「SSH」命令
  • USER_NAME: 在此代指服务商所提供的 VPS 用户名,一般默认为「root」
  • SERVER_IP_ADDRESS: 服务商所提供的 IP 地址

随后根据提示输入你的密码,来登陆 VPS。 如果是以私钥登陆,这里则可以不用输入密码,安全地自动登陆。(关于私钥的路的设置,我们接下来再说)

Tips: 如果这是你通过服务商提供的初始密码来登陆 VPS。为了安全起见,建议你最好尽快修改你的「root」密码,并且创建一个新的用户来访问 VPS

关于「root」用户

「root」用户在 Linux 中是拥有最高的管理员权限,他有着完整的访问权、控制权、支配权,并且多数 Linux 发行版在「root」权限下并不会提示一些强大的命令对系统有着破坏性的危险。
一部分命令在「root」权限下十分的危险。由于「root」用户拥有对所有目录完整的控制权并且不需要确认,这使得在「root」权限下的命令能作用于计算机上的所有目录。

0x02 创建新用户

首先,用 adduser 命令创建新用户。

adduser USER_NAME
  • adduser: Linux 中创建新用户的命令
  • USER_NAME: 在此代指你想创建的用户名,你可以用你喜欢的任何名称来替换他

随后用 passwd 命令为用户创建密码。

passwd USER_NAME
  • passwd Linux 中为用户设置密码的命令
  • USER_NAME: 在此代指你想设置密码的用户名,在此,你应该使之前创建的用户名

0x03 为新用户授予「root」权限

新用户是普通用户,没有「root」权限,这使得在你想要做一些对系统的修改,以及安装软件时需要切换到「root」用户。这很不方便,而且也不安全。为了解决这个问题,我们需要为我们的新用户赋予通过在命令前添加 sudo 前缀来暂时取得「root」权限的能力。
我们可以通过将我们的新用户添加到「wheel」用户组,来使他拥有使用 sudo 的权限。 首先我们确认我们当前是以「root」登录,随后我们可以使用 gpasswd 命令来把我们的新用户添加到「wheel」用户组。

gpasswd -a USER_NAME wheel
  • gpasswd Linux 中为用户设置用户组的命令
  • USER_NAME: 在此代指你想设置用户组的用户名,在此,你应该使用之前创建的用户名

现在,我们的用户就拥有使用 sudo 前缀来暂时获取「root」权限的能力了。

0x04 添加私钥验证

创建秘钥对

你可以在你的计算机上使用 ssh-keygen 命令来生成「秘钥对」

ssh-keygen

当生成完成,你的「Terminal」会这样显示:

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/USER_NAME/.ssh/id_rsa):

直接回车确认你的秘钥保存位置。
接下来,「Terminal」会让你输入你的秘钥密码。如果你直接回车留空,砸你使用秘钥登陆的时候你只需要验证你的私钥即可。而如果你在此设置了密码,在使用秘钥登陆的时候将同时使用私钥以及密码登陆。无论你使用那种方式,他们都要比使用普通密码登陆要安全得多。

这个命令在你当前用户的「HOME」中的「.ssh」目录创建了一对私钥 id_rsa 和公钥 id_rsa.pub。请记住不要把私钥提供给任何没有权限访问你的服务器的人。

复制其中的公钥到你的服务器

你可以在你的电脑上使用 cat 命令去查看你的公钥

cat ~/.ssh/id_rsa.pub

这条命令运行后你的「Terminal」上已改会显示类似这样的公钥

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBGTO0tsVejssuaYR5R3Y/i73SppJAhme1dH7W2c47d4gOqB4izP0+fRLfvbz/tnXFz4iOP/H6eCV05hqUhF+KYRxt9Y8tVMrpDZR2l75o6+xSbUOMu6xN+uVF0T9XzKcxmzTmnV7Na5up3QM3DoSRYX/EP3utr2+zAqpJIfKPLdA74w7g56oYWI9blpnpzxkEd3edVJOivUkpZ4JoenWManvIaSdMTJXMy3MtlQhva+j9CgguyVbUkdzK9KKEuah+pFZvaugtebsU+bllPTB0nlXGIJk98Ie9ZtxuY3nCKneB+KjKiXrAvXUPCI9mWkYS/1rggpFmu3HbXBnWSUdf localuser@machine.local

选择这条公钥,并且将它复制。

为了让你 VPS 上的新用户上启用私钥登陆,你必须将你的私钥添加到这个用户的「HOME」中的「.ssh」目录中。

如果你是以「root」用户登陆的,你需要用 su 命令来切换到你的新用户。

su USER_NAME
  • su Linux 中切换用户的命令
  • USER_NAME: 在此代指你想切换的用户名,在此,你应该使之前创建的用户名

随后在用户的「HOME」目录创建一个「.ssh」目录,并且设置权限

mkdir ~/.ssh
chmod 700 ~/.ssh

之后在这个目录中创建用于存放公钥的「authorized_keys」目录。

touch ~/.ssh/authorized_keys
echo 'PUBLIC_KEY' > ~/.ssh/authorized_keys 
  • PUBLIC_KEY: 用你之前复制的公钥来替换。

随后使用 exit 命令返回到 root 用户

0x05 设置「SSH」服务

现在我们拥有了一个有着秘钥的用户了,这时我们就可以设置「SSH」服务。修改登陆端口、禁用密码登陆、禁止「root」用户远程登陆。

我们可以在「root」用户下用以下命令设置「SSH」服务

vi /etc/ssh/sshd_config

他会打开一个编辑器,我们可以按 i 来进入编辑模式。

  • 修改登陆端口 – 找到 #Port 22 并将它修改成 Port PORT_NUMBER,「PORT_NUMBER」可以是 1000 - 65535 中的任意一个
  • 禁止密码登陆 – 找到 #PasswordAuthentication yes 并将它修改成 PasswordAuthentication no
  • 禁止「root」用户远程登陆 – 找到 #PermitRootLogin yes 并将它修改成 PermitRootLogin no

按「ESC」键并在英文输入状态下输入 :wq 来保存文件。随后使用这条命令来重启「SSH」服务

systemctl reload sshd

这时候先不要急着关掉终端,我们需要测试一下我们的之前的设置是否有效。开一个新的「Terminal」并使用 SSH 命令来登录,这时登陆的用户名应该改成之前创建的用户名。

如果登陆成功,那么恭喜你,你的服务器已经成功以最安全的方式初始化了,你可以好好「调教」他了。

参考文档

  1. Initial Server Setup with CentOS 7 | DigitalOcean