[转载]unix环境高级编程备忘:理解保存的设置用户ID,设置用户ID位,有效用户ID,实际用户ID...

转载自http://www.cnblogs.com/stemon/p/5287631.html

一、基本概念

实际用户ID(RUID):用于标识一个系统中用户是谁,一般是在登录之后,就被唯一的确定,就是登录的用户的uid。

有效用户ID(EUID):用于系统决定用户对系统资源的权限,也就是说当用户做任何一个操作时,最终看它有没有权限,都是在判断有效用户ID是否有权限。如果有,则ok,否则报错不能执行。在正常的情况下,一个用户登录之后(假设是A用户),A用户的有效用户ID和实际用户ID是相同的,但是如果A用户在某些场景中想要执行一些特权操作,能顺利的执行吗?上面说到了用户的任务操作,linux内核都是通过检验有效用户ID来判断当前执行这个操作的用户是否具有权限。这里的A用户想要执行的是特权操作,A用户没有这个权限,所以A用户就只能通过一定的手段来修改当前的有效用户ID使其具有执行特权操作的权限。

这里总结一句话:为什么要修改进程的有效用户ID,就是想在某一时刻能够执行一些特权操作。

设置用户ID位:用于对外的权限的开放,它的作用是修改进行的有效用户ID,给进程赋予临时的特权。

保存的设置用户ID:是有效用户ID副本,既然是有效用户ID的副本,那么它的作用肯定是为了以后恢复有效用户ID。

这里涉及很多的ID,通过下图看一下这些ID都是属于谁:

下面说一下文件设置用户ID位,这个ID仅仅是一个二进制的bit位,在文件stat结构的st_mode成员中,对于一般的文件,该位是置为无效的,只有可执行文件的该位是置为有效的。

二、改变三个用户ID的方法

下面这幅图给出了改变实际用户ID、有效用户ID和保存的设置用户ID的方法

再来一幅图看一下文件的ID和进程的ID在权限访问上的对应关系。对于一个普通文件,有三个ID,这三个ID对应三组权限,这三组权限控制着进程对该文件的访问权限。

在注意一点:ID并不是一个int或者一个标识,他是一个操作系统用户的标号,该用户创建的所有的进程都是这个ID。

对于linux系统,某个用户登录后,创建一个文件,那个这个文件的用户ID就是这个用户的ID。该用户创建的所有的进程都可以访问这个文件,因为该用户创建的进程的实际用户ID和有效用户ID都是这个用户的ID。但是当一个用户创建的进程要去访问其他用户创建的文件的时候,就需要用到有效用户ID的改变,来能够有权限访问这个文件。

1. 进程打开、创建、删除文件时的权限测试?

测试的参与者是进程的有效用户id、有效组id、文件的拥有者id、文件拥有者组id。

(1)进程的有效用户id是0(超级用户),则允许访问;

(2)进程的有效用户id等于文件拥有者id,则按照拥有者的权限访问;

(3)进程有效组id或附加组id之一等于文件拥有者组id,则按照文件拥有者组的权限访问;

(4)否则,按照文件的其他用户访问权限访问;

上述的四步是按续依次进行的。

2. 什么时候用到设置用户id和设置组id?

当进程通过exec函数执行某个文件的时候,而且文件的设置用户id只会影响到进程的有效用 户id

(其实也足够了,因为只有有效用户id参与权限测试),这样说不够严谨,因为进程的保存设置用

户id和保存设置组id会被exec函数从有效用户

id和有效组id复制过来,所以保存的设置用户id和保存的设置组id也会随之改变。

(1)当文件的设置用户id位和设置组id位没有打开:

进程的有效用户id和有效组id保持不变,严格按照第2步进行权限测试;

(2)文件的设置用户id位和设置组id位被打开:

exec函数才会把进程的有效用户id和有效组id设置为文件拥有者的用户id和组id,这时再进

行权限测试,进程就拥有了和文件拥有者一样的访问权限。

3. 进程保存设置用户id和保存设置组id有什么用?

顾名思义,这两个id存在的价值就是保存,保存谁呢?保存有效用户id和有效组id。当进程的

实际用户id和有效用户id不同时(组id同理),保存的设置用户id才有意义。因为这样就可以通

过调用setuid()把有效用户id切换为与进程的实际用户id或保存的设置用户id相同的值,不保存下

来,我们就弄丢了。

三、具体实例分析

实例分析一:

如何在权限不够的情况下执行特权权限,具体的方法就是更改进程的有效用户ID。

对于linux系统来说,用户的密码都存放在/etc/shadow文件下,查看一下这个文件的权限:

假如我是一个普通的用户,显然我是可以修改我自己的密码的,通过passwd命令,无可厚非,自己修改自己的密码当然是允许的。

但是仔细想想有没有什么不对的地方,作为一个普通的用户登录后,我的所有的进程的实际用户ID和有效用户ID都应该是我自己(这个用户)的UID。从上面对/etc/shadow文件用户ID和所属的组ID看,我不具备修改这个文件的权限,那么执行passwd命令是怎么修改我的密码的呢?

根据上面所讲的知识,决定进程对文件的访问权限的是执行操作时的有效用户ID,所以在执行passwd命令时,进行的有效用户ID肯定不是我这个普通用户的UID,一定被修改过了。

还有一点,在执行passwd这个命令的时候,在磁盘上肯定有一个可执行的文件,下面看看这个可执行文件的权限:

我们看到了一个s,这就是使用户设置ID位有效,上面说过这个位的作用就是修改执行这个可执行文件的进程的有效用户ID,那么我么来看看他是怎样修改执行passwd命令的进程的有效用户ID的。

首先看一下命令的执行的过程,当普通用户执行passwd命令时,shell会fork出一个子进程,此时该进程的有效用户ID还是这个普通用户的ID,然后exec程序执行/usr/bin/passwd这个例程(可执行文件)。通过上面的表我们就能知道,exec发现/usr/bin/passwd这个可执行文件有SUID为,于是会把进程的有效用户ID设置成可执行文件的用户ID,显示是root,此时这个进程就获得了root的权限,得到了读写/etc/shadow文件的权限,从而普通用户可以完成密码的修改。exec进程退出后,会恢复普通用户的有效用户ID为实际用户ID(也就是该普通用户的ID),这样就保证了不会是普通用户一直具有root权限。

在exec时,修改进程的有效用户ID为文件的用户ID,还是恢复进程的有效用户ID为进程的实际用户ID,这些都是linux内核完成的,用户是不能干预这些步骤的。

这样的过程既实现了普通用户权限的暂时的提升,不让普通用户长久的拥有root权限。同时即使在普通用户拥有root权限的这段短暂的时间里,普通用户也不能为所欲为,因为普通用户的这个进程必须按照/usr/bin/passwd这个可执行文件的指令内容执行,不能干之外的任何事情,而这个可执行文件又是root事先写好的,多么完美的设计啊~~

这就是设置用户ID为的作用,它的存在就是为了普通用户能够在某些时候获取一段时间的超级权限,但是你可能疑问,为什么不能用setuid直接修改呢?

如果这里可以用setuid直接修改进程的有效用户ID来获得特权权限,那么整个系统的超级权限就不可控制了,这违背了最小权限模型。所以linux的设计是:setuid在非特权用户下面,有效用户ID只能设置成为实际用户ID或者保存的设置用户ID。保存的设置用户ID又是有效用户ID的副本,有效用户ID只能是实际用户ID或者文件的所有者ID(在设置了保存用户ID位时)。

这样你就不能将有效用户ID设置成随意的值,所以对普通用户创建的任何文件,如果没有得到超级用户的授权,那么无论怎么编写代码来设置运行进程的有效用户ID或者设置用户ID位,由于这个可执行文件是普通用户自己编写的,所以权限根本没有任何改变。这里就是说只有root自己创建的可执行文件并且设置了用户ID位,才能够提升执行该可执行文件的进程的权限。

实例分析二:

上面的例子中没有用到保存的设置用户ID,看看这个ID的作用。既然保存的设置用户ID是有效用户ID的副本,那么肯定是为了在某个时刻用于恢复原先的有效用户ID的,这样就能够实现用户权限的切换。

例如:man命令(这是AUP上面的例子,当然实际linux上好像不是这么实现的,不过还是哪这个当做例子说明)

man程序文件的所有者和其它属组通常都是man自身保留的用户和组,man可能需要执行许多其它命令,以处理包含显示手册页的文件,为了防止被欺骗和重写错误文件,man在两种权限之间切换。运行man命令用户的权限,拥有man可执行文件用户的权限。下面列出其工作步骤:

(1)man拥有者是名为man的用户,且设置用户ID位已经设置。当我们exec此程序的时候,用户ID的情况是:

1
2
3
实际用户ID=我们的用户ID
有效用户ID=man  //设置用户ID位已经设置,有效用户ID改变
保存的设置用户ID=man

(2)进程访问需要的配置文件和手册页,这些文件由man用户拥有,因为有效用户ID是man,所以可以访问。

(3)man代表我们执行任何一个命令之前,调用setuid(getuid()),我们不是超级用户,所以仅仅改变有效用户ID,现在用户ID的情况变为:

1
2
3
实际用户ID=我们的用户ID(没有改变)
有效用户ID=我们的用户ID
保存的设置用户ID=man

看出来了吧,如果不保存下来,我们就把man用户丢了,再想setuid(man)就不会成功了,因为只允许将有效用户ID设置为与实际用户ID或者保存的设置用户ID相同的值。这时候,我们做回了自己。就只能访问我们通常可以访问的东西,没有特殊的权限了。man代表我们安全执行一次过滤。

(4)执行完过滤后,man再调用setuid(euid)(这里的euid是man的数值用户id,man自己通过geteuid获得并保存)。因为euid等于保存的设置用户ID,设置成功。

我们这时得到:

1
2
3
实际用户ID=我们的用户ID(未改变)
有效用户ID=man
保存的设置用户ID=man(未改变)

(5)因为有效用户ID是man,所以现在可以对其他文件进行操作了。  

四、新文件和新目录的所有权

1. 新文件的用户ID设置为进程的有效用户ID

2. 新文件的组ID有两种情况:

  • 新文件的组ID为进程的有效组ID
  • 如果新文件的组ID所在的目录的设置组ID位设置了的话,新文件的组ID将设为目录的组ID。

3. 其他

  • mkdir函数自动的传递了目录的设置组ID位
  • access函数是用设计用户ID和实际组ID来进行访问权限的测试的,如果你只是想测试一下实际用户所拥有的权限,这个函数就可以了。

五、编程应用

1. 在执行exec前后,进程的实际用户ID和实际组ID不变,而有效ID取决于所执行的程序文件是否设置了设置用户ID位和设置组ID位, 如果设置了设置用户ID位,则有效用户ID变成程序文件所有者ID,否则有效用户ID不变。对组ID处理方式与此相同
2. 保存的设置用户ID是由exec复制有效用户ID后得来的,所有说设置用户ID是有效用户ID的副本!
3. 一般设计应用程序时,总是试图使用最小特权模型,依照模型,程序应当只具有为完成任务所需的最小特权.
4. 使用函数:

1
2
3
4
5
6
7
8
#include <unistd.h>
int setuid(uid_t uid); //设置实际用户ID和有效用户ID,如果进程为超级用户,则会设置实际、有效、保存的设置用户ID
int setgid(gid_t gid); //设置实际组ID和有效组ID
int setreuid(uid_t ruid, uid_t euid); //交换实际用户ID和有效用户ID
int setregid(gid_t rgid, gid_t egid);
int seteuid(uid_t uid); //更改有效用户ID
int setegid(gid_t gid);

注意: 
根据书上来看,特权用户使用这几个函数的时候,都是直接用参数的值来设置实际用户ID或者有效用户ID,这些值都可以是任意的。
例如:setreuid(ruid, euid), 如果是特权用户,则直接设置实际用户ID为ruid,有效用户ID为euid。

但非特权用户就不行了,非特权用户用setuid(),seteuid()则只能将有效有户ID设置为实际用户ID或保存的设置用户ID,如果不是这两个数,设置失败!

对编程应用方面的总结:
非特权用户不能指定任意的有效用户ID, 结合其他几个函数来交换或设置有效用户ID, 与设置用户ID位一起实现权限的控制。

转载于:https://www.cnblogs.com/J1ac/p/8893840.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280533.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

django20:BBS网页设计/注册功能/验证码代码

表设计 注册功能 """ 1.注册功能需要forms组件 不同功能&#xff0c;可单独一个py文件2.利用forms组件渲染前端标签1.利用ajax提交2.forms组件获取用户数据的数据。$(#form).serializeArray()获取forms标签所有用户普通键值对的数据3. 手动渲染头像label里面内…

用最少的代码打造一个Mini版的gRPC框架

在《用最少的代码模拟gRPC四种消息交换模式》中&#xff0c;我使用很简单的代码模拟了gRPC四种消息交换模式&#xff08;Unary、Client Streaming、Server Streaming和Duplex Streaming&#xff09;&#xff0c;现在我们更近一步&#xff0c;试着使用极简的方式打造一个gRPC框架…

Windows 10的下一个更新将在您观看视频时隐藏通知

Windows 10’s Focus Assist feature temporarily hides incoming notifications. In Windows 10’s next update, Focus Assist can activate when you’re using any full-screen app, whether that’s YouTube in a browser, Netflix, or a desktop video player like VLC. …

Ubuntu安装Samba文件共享服务器(NAS)

终于有点时间来解决下家中NAS需求了。一般自制NAS&#xff0c;只有选Samba。速度比FTP快&#xff0c;便利性比Windows文件夹共享好&#xff0c;设置多等等。 ▶参考&#xff1a;samba简介 安装Samba $ sudo apt-get update $ sudo apt-get install samba samba-common-bin 核心…

django21:admin后台管理\media配置\图片防盗链\暴露后端资源\路由分发\时间分类

admin后台管理 创建超级用户 createsuperuser 1.到应用下的admin.py注册模型表 from django.contrib import admin from blog import models # Register your models here.admin.site.register(models.UserInfo) admin.site.register(models.Article) admin.site.register(m…

Flask博客开发——Tinymce编辑器

之前Flask博客的文本编辑器比较简陋&#xff0c;这里为博客添加个优雅易用的Tinymce文本编辑器。 github见&#xff1a;https://github.com/ikheu/my_flasky 1 项目中添加Tinymce 下载好Tinymce包以及语言包&#xff0c;并添加到项目中。添加到项目的方法&#xff0c;参考了这篇…

Hello, Raspberry Pi.

1.概要最近在研究自动升级开源项目的时候偶然想到IoT领域的自动升级&#xff0c;突然想起2016年买的树莓派&#xff08;Raspberry Pi&#xff09;。那就分享一下如何入门树莓派的教程&#xff0c;我当时一共买了两块一款是Raspberry Pi 3b&#xff08;2016年价格259元去年以抽奖…

supersu_SuperSU已从Play商店中删除,这是替代使用的方法

supersuSuperSU has long been a staple in the rooted Android community. For years, the process for getting a rooted handset was: unlock the bootloader, flash a custom recovery, install SuperSU. That’s just how it was. 长期以来&#xff0c;SuperSU一直是扎根于…

django项目开发1:搭建虚拟环境

需求 不同项目依赖不同模块版本&#xff0c;不能共用一套环境&#xff0c;虚拟环境。在系统的python环境安装 安装 pip3 install virtualenv pip3 install virtualenvwrapper-win环境变量 # 配置环境变量&#xff1a; # 控制面板 > 系统和安全 > 系统 > 高级系统设…

div 包裹_如何查看到达之前收到的包裹和邮件

div 包裹The United States Postal Service, UPS, and FedEx all offer online dashboards where you can see exactly what packages (and letters, in the case of the US Postal Service) are scheduled to arrive at your address. They’ll even email and send you text …

py文件的运行

安装过程及配置 安装过程准备&#xff1a; 下载好Python的安装程序后&#xff0c;开始安装&#xff0c;在进入安装界面后一定确保勾选将Python加入到系统环境变量的路径里。如图所示&#xff1a; 2如果没有选取&#xff0c;那么按照下面的步骤进行操作。在桌面上用鼠标右键点击…

网络编程基础(一)

一.楔子 你现在已经学会了写python代码&#xff0c;假如你写了两个python文件a.py和b.py&#xff0c;分别去运行&#xff0c;你就会发现&#xff0c;这两个python的文件分别运行的很好。但是如果这两个程序之间想要传递一个数据&#xff0c;你要怎么做呢&#xff1f; 这个问题以…

dotnet-exec 让 C# 程序更简单

dotnet-exec 让 C# 程序更简单Introdotnet-exec是一个可以执行 C# 程序而不需要项目文件的命令行工具&#xff0c;并且你可以指定自定义的入口方法不仅仅是Main方法在 python/NodeJs 里&#xff0c;可以使用python xx.py/node xx.js来运行代码&#xff0c;在 C# 中一般是需要项…

office数据集dslr_如何将照片从DSLR无线传输到智能手机

office数据集dslrYou’ve got a great digital camera. You’ve got all your social media apps on your phone. Wouldn’t it be nice if you could snap a beautiful shot with your DSLR and shuttle it right over to your phone to throw up on Facebook or Instagram? …

文件管理、命令别名和glob

一、复制命令:cp src dest1.如果scr是文件a.如果dest不存在&#xff0c;则新建dest并将src的内容填充到dest里b.如果dest存在&#xff0c;则会用src里的内容覆盖dest里的内容&#xff0c;即覆盖dest2.如果src是目录a.如果dest不存在&#xff0c;则新建dest,然后把src下的内容复…

django版本区别/与版本匹配

一、区别 路由层 1.django 1.x路由层使用url方法 django 2.x和3.x版本使用path方法 url() 第一个参数支持正则 path()第一个参数是不支持正则的 可以使用 re_path替代url() from django.urls import re_path # django2.0中的re_path #不建议导入url,不能区分版本 #from djang…

中兴面试一个星期没有回音_如何在没有回声的情况下从亚马逊获取即时时尚建议...

中兴面试一个星期没有回音The Echo Look is a new device from Amazon that’s able to take a look at your outfits and tell you which one looks the best on you. However, you actually don’t need the Echo Look to get this kind of instant fashion advice from Amaz…

table分页的简单实现逻辑

为什么80%的码农都做不了架构师&#xff1f;>>> //table分页函数showPageNum: function(pageNum, allPageNum) { //pageNum点击第几页&#xff0c;allPageNum总页数$(".c_page .c_page_list").children().remove();for(var i1;i<allPageNum;i){var p…

Cocos Creator Ui系统

为什么80%的码农都做不了架构师&#xff1f;>>> 游戏场景&#xff1a;开发时组织游戏内容的中心&#xff1b;其中渲染根节点Canvas&#xff0c;包括属性 Design Resolution&#xff08;设计分辨率&#xff09; fit width,fit height 设计分辨率是内容生产者在制作场…

推荐一个使用 .NET 6 开发的开源媒体系统

你好&#xff0c;这里是 Dotnet 工具箱&#xff0c;定期分享 Dotnet 有趣&#xff0c;实用的工具和组件&#xff0c;希望对您有用&#xff01;什么是 Jellyfin ?Jellyfin 是一个免费的媒体系统&#xff0c;它可以让您更好的管理媒体&#xff0c;包括电影&#xff0c;音乐&…