Linux碎点

2015/4/6 13:43 下午 posted in  舶来 comments

Linux下如何编译并运行C程序

GCC是Linux操作系统下一个非常重要的源代码编译工具,有着许多重要的选项,支持许多不同语言的编译,如C、C++、Ada、Fortran、Objective、Perl、Python、Ruby以及Java等,甚至Linux的许多内核和许多其他自由软件以及开放源码应用程序都是用C语言编写并经gcc编译而成的.

1.编译单个源文件

[例如]在屏幕上打印”Hello,Linux.”

[源代码]

include

include

int main(int argc,char **argv)

{

printf(“Hello,Linux.\n”);

exit(0);

}

将源文件保存为hello.c,开始进行编译

$gcc -o hello hello.c

编译成功完成后,在当前路径下,生成一个名为hello的文件,然后执行

$./hello

在屏幕上,你将会看到打印结果:Hello,Linux.

说明:在默认情况下,编译成功完成后,会在当前路径下,生成一个名为a.out的文件,然后执行$./a.out便可打印结果,但通常可以通过选项-o来指定自己的可执行程序名称;

2.编译多个源文件

3.使用外部函数库

4.使用共享函数库和静态函数库

5.gcc选项详细描述

Linux普通用户无法使用sudo处理及sudoers设置

http://www.tuicool.com/articles/bYvqYfn

Linux下我们经常使用的SSH远程连接到系统进行操作,而为了安全,一般使用的是非root用户连接,只有在必要的时候,我们才会使用sudo切换到root帐户下进行操作,以保证系统尽可能的安全和不被损坏。然而,在有的时候我们通过普通用户SSH连接到Linux的时候,使用sudo来执行身份切换的时候,系统会报错(以下是CentOS6.4下的报错):

对不起,用户 yourusername 不能在 CentOS 上运行 sudo。

或者

Sorry,user yourusername may not run sudo on CentOS

这种情况下,为了让我们的用户能够正常的使用sudo,需要通过修改 /etc/sudoers 文件。

添加下面一行到:/etc/sudoers,即可让该用户使用sudo

yourusername ALL=(ALL) ALL

这种修改是将所有的权限都赋值给了yourusername,为了sudo这个命令,就这么ALL几下,似乎有点不负责任啊,有木有?

sudoers文件默认是只读的,因此不能直接修改。网上很多方法是使用chmod来修改sudoers的权限后再通过编辑器(vi/vim etc.)来修改sudoers内容,之后再将sudoers文件的权限恢复,来达到修改sudoers的目的。这种方法确实能够修改sudoers,但是却没有办法保证sudoers文件的正确性,如果修改出现错误,将导致sudoers(sudo)不能正常的工作。更正确的做法是直接使用sudoers的专用编辑器: visudo 来编辑sudoers文件。

visudo

visudo默认的编辑器是vi,如果你需要修改你的默认编辑器,可以通过添加EDITOR="" 来修改。

EDITOR="/usr/bin/vim -p -X" visudo

如果要永久改变默认编辑器,只要将EDITOR设置为环境变量

export EDITOR="/usr/bin/vim -p -X"

使用 visudo 来编辑sudoers的好处是:当我们完成sudoers的编辑时,系统会自动检测我们sudoers的格式是否正确,从而保证sudoers文件的正确性。

其实,sudoers文件是非常简单的,其内容只包含两种,第一种是别名(Aliases,基本变量定义),第二种是用户规范描述(user specifications,指定某用户可以运行的内容)。而这两种内容都是通过 扩展巴科斯范式(EBNF) 1 来进行定义。一旦定义了别名,在用户说明中,就可以使用别名来简化给用户定义运行内容。如果同一个用户在sudoers文件中能够找到多条说明,那么将使用找到的最后一条。

sudoers的别名包含四种:User_Alias,Runas_Alias,Host_Alias和Cmnd_Alias。

User_Alias是用户别名,这个和系统中的group有点类似。通过用户别名,在sudoers中,可以将一个或者多个用户用别名来替代。

定义一个用户别名

User_Alias OPERATORS = operator1,operator2,remote_admin

注意:
1. 等号后面的都是系统中的用户名,用户ID,组,组id等组成,多个用逗号分隔,具体信息可参看文后参考内容 sudoers 2
2. 别名只能是大写字母开头的,并由大写字母,下划线和数字组成的字符串

Runas_Alias和User_Alias类似,但不同的是Runas_Alias指明的是用户将要运行命令的身份。Runas_Alias可以包含Runas_Alias别名(User_Alias是包含User_Alias别名)。

同时要注意的是,上面两个别名在匹配的时候使用的是字符串匹配法则,也就是说,当两个不同用户名的用户,即使使用了同一个用户ID,在实际情况下,也会被认为是不同的。要避免这种情况,可以考虑使用用户的ID来替代用户名。如:

Runas_Alias ROOT = #0

所有的用户ID为0的,统归为ROOT别名

Host_Alias是主机别名,指定规则适用的主机列表。

Host_Alias SERVERS = 192.168.0.1, 192.168.0.2, server1

注意:

1. Host_Alias中,只能使用真实的地址,这就意味着127.0.0.1这种地址是永远不会被匹配到的。而localhost要只有在真有主机的主机名为localhost的时候才能被匹配。

2. 如果IP地址没有给定掩码,sudo自动会搜寻本地网卡上对应匹配的掩码地址来作为默认的网络掩码。

Cmnd_Alias是命令别名,指定用户能够运行的某一类命令的列表。可包含一个,或多个命令(带参数),目录,或者其他的命令别名。

Cmnd_Alias SHUTDOWN_CMDS = /sbin/poweroff, /sbin/reboot, /sbin/halt

所有的关机命令

Cmnd_Alias ADMIN_CMDS = /usr/sbin/passwd, /usr/sbin/useradd, /usr/sbin/userdel, /usr/sbin/usermod, /usr/sbin/visudo

所有的用户管理命令

注意:

1. 命令列表中如果包含目录(以/结束),那么该目录下(不含子目录)的所有可执行文件都被赋予了执行权限,这和使用通配符*类似;

2. 命令列表中务必使用全路径名,如果不使用完全限定名,将意味着恶意用户可以创建同名文件并在切换后的用户下运行,这将给系统带来未知的安全风险;

3. 当命令列表中的命令需要带参数的时候,如果出现特殊字符(’,’,’:’,’=’,’\’),将需要使用反斜杆(’\’)进行转义。

通过上面四种别名,我们能够定义出特定的用户,主机和命令列表,在实际运行中,我们如果要对这些特定的列表的某些运行时 配置项 3 进行修改,我们可以通过Default来完成。

Default对于前面四种别名的限制格式各有不同,定义如下:

EBNF

Default_Entry ::= ('Defaults' |'Default' '@' Host_List |'Default' ':' User_List | 'Default' '!' Cmnd_List | 'Default' '>' Runas_List ) Parameter_List

Parameter_List ::= (Parameter '=' Value |Parameter '+=' Value |Parameter '-=' Value |'!'* Parameter)[ , Parameter_List]

定义中 *_List可以是别名也可以是特定的具体信息(如:用户名)。

别名之后,就是具体的用户规范描述(User Specification)了。

User Specification表述的主要意义就是: 哪些用户在哪些环境里可以作为哪些用户来运行哪些程序 。用EBNF来表示这个定义如下:

User_Spec ::= User_List Host_List '=' (Cmnd_Spec | Cmnd_Spec ',' Cmnd_Spec_List) \
(':' Host_List '=' Cmnd_Spec_List)*

Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Solaris_Priv_Spec? Tag_Spec* Cmnd

Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'

SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')

Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')

Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |
'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')

看起来很复杂,来个栗子也许会好很多:

在SERVERS环境中OPERATORS可以以ROOT角色运行SHUTDOWN_CMDS

OPERATORS SERVERS = (ROOT) SHUTDOWN_CMDS

在所有的环境中yourusername都可以切换到所有账户下运行所有的命令

yourusername ALL = (ALL) ALL

yourusername用户在SERVERS上面执行关机操作

yourusername SERVERS = /sbin/halt, /sbin/poweroff

以root来执行关机操作,但以operator来执行kill命令

yourusername SERVERS = (root) SHUTDOWN_CMDS, (operator) /bin/kill

sudo -u来选择用户

仅以operator组来执行kill命令

yourusername SERVERS = (:operator) /bin/kill

注意,在sudo的时候需要使用-g配合,但kill还是由yourusername执行

无需使用密码(不用校验operator身份),即可以operator身份来执行kill命令

yourusername SERVERS = (operator) NOPASSWD: /bin/kill

至于SELinux_Spec和Solaris_Priv_Spec一般不会用到,SELinux_Spec是在支持SELinux的系统中有效,而Solaris_Priv_Spce则是针对Solaris系统的配置。Tag_Spec相对前两个在Linux系统来说就实用的多,Tag_Spec共有10个可选tag参数,可以分成5组,每组由互斥的两个tag参数构成,分别是:NOPASSWD和PASSWD,NOEXEC和EXEC,SETENV和NOSETENV,LOG_INPUT和NOLOG_INPUT,LOG_OUTPUT和NOLOG_OUTPUT。不同组别的tag参数可以同时使用,在使用Tag_Spec之后,如果没有使用相反的tag参数覆盖,则同行后面的命令将会继承tag参数设置。下面是5组tag的说明:

| Tag参数 | 作用描述 |
| NOPASSWD,PASSWD | 标识是否需要身份验证 |
| NOEXEC,EXEC | 是否限制程序进一步运行命令(动态链接有效) |
| SETENV,NOSETENV | 标志如何处理环境变量,建议不用SETENV(默认是NOSETENV),SETENV会禁用通过命令行传递的env_reset参数 |
| LOG_INPUT,NOLOG_INPUT | 输入日志开启标志,LOG_INPUT开启后,所有输入信息都会被记录,如密码这类敏感信息同样会以明文形式记录下来 |
| LOG_OUTPUT,NOLOG_OUTPUT | 输出日志标志,开启后,所有的输出都会被保存在文件中 |

到此为止,sudoers文件的主体就已经完成了,根据这些东西,你就可以顺利修改sudoers了。

高级部分:

1. 可以通过#includedir,#include两中方式将其他的sudoers文件包含进来;

2. 要注释,用#,当然,第一点中的这个和#后面跟数字的要小心(猜猜看,是神码?);

3. 在编辑中,为了简便,你可以在主机列表,路径名称和命令列表中使用通配符(不是正则),通配符:(匹配0或多个),?(匹配单个字符),[…](匹配范围内的任一字符),[!…](说了不是正则了,匹配任一不在指定范围内的字符),\x(转义特殊字符,如:,?, [, ])。例外:””双引号在命令行参数中表示的是命令不允许带任何参数;传递给sudoedit内置命令的命令行参数必须包含路径名称,因此斜杆(/)不会被通配符匹配;

4. 在Alias,Defaulsts,User Specification中设定值的时候可以使用感叹号(!),表示取非(排除),当然,如果你觉得多几个感叹号能加强效果也是可以的,记住单数表示取反,偶数是双重否定,直接抵消作用即可。同时也要注意,这个感叹号有时候会失效,会带来一些安全风险;

5. 上一点的一点特例:

可Runas除了root之外的所有用户

User_Alias SPECIALUSERS = ALL,!root

这个的作用不同于上面这行规则,sudo匹配的时候是不匹配root

同时也不会匹配任何其他用户

User_Alias SPECIALUSERS = !root

6. 规则太长,一行写不下?试试行尾加上反斜杆(\),然后换到第二行继续写。

7. MitchellChu本身也是菜鸟一枚,共勉! (这个最高级:P)

最后回归开篇第一个问题,你觉得这种配置有问题么?

参考:

1. 扩展巴科斯范式(EBNF): Extended Backus-Naur FormBackus-Naur Form , 巴科斯范式扩展巴科斯范式

2. sudoers: Sudoers Manual

3. Sudoers的Default可配置参数请参看2中Sudoers Manual中的SUDOERS OPTIONS

4.其他一些参考: Archlinux SUDO , Ubuntu Sudoers , sudo.ws SUDO manual