第九章

9-1 在下列每种情况中,假设进程用户ID的初始值分别是real(实际)=1000、effective(有效)=0、saved(保存)=0、file-system(文件系统)=0。当执行这些调用后,用户ID的状态如何?

  • a) setuid(2000);
  • b) setreuid(-1, 2000);
  • c) seteuid(2000);
  • d) setfsuid(2000);
  • e) setresuid(-1, 2000, 3000);

我们总结一下课本上有关这几个函数的知识点:

set是函数的开头,后面r是真实id,e是有效id,s是保存id,f是文件id,uid是进程凭证。

对于特权级进程,也就是有效id是0的id,按照函数名可以修改对应标志位到任意值。

对于非特权级进程,有效id不是0,情况比较复杂。

  • setuid、seteuid只能修改有效ID
  • setresuid能修改所有ID
  • setreuid能修改实际id和有效id,但是对实际id不能修改为保存id。

额外的,setreuid无论在哪种情况下,当设置了实际id,或有效id发生变化,保存id将等于有效id。

可以看出setreuid情况是最复杂的,最好不要用这种函数。但是在其他Unix系统中,不提供这个函数。

原来的状态:

real effective saved file-system
1000 0 0 0

a 中尝试修改用户id为2000,有效是特权0情况下,修改所有id,并成功。同时文件id也跟着变化,现在是:

real effective saved file-system
2000 2000 2000 2000

b 中尝试修改有效用户id为2000,成功,同时文件id变化为2000,现在是:

real effective saved file-system
1000 2000 0 2000

c 中尝试修改有效用户id为2000,并触发了saved修改条件,有效id和保存id都改为2000。

real effective saved file-system
1000 2000 2000 2000

d 尝试修改文件系统id,有效。

real effective saved file-system
1000 0 0 2000

e 尝试修改有效id和保存id,有效。

real effective saved file-system
1000 2000 3000 0

9-2 拥有如下用户ID 的进程享有特权吗?

real = 0 effective = 1000 saved=1000 file-system=1000

因为特权只和effective位置有关,所以没有特权。

9-3 使用setgroups()与库函数从密码文件、组文件中获取信息,以实现initgroups()。请注意,欲调用setgroups,必须有特权才可以。

因为c++可以进行更方便的字符串操作,我们使用c++来实现。

#include <unistd.h>
#include <grp.h>
#include <stdio.h>
#include <pwd.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>

using namespace std;

void SplitString(const std::string &s, std::vector<std::string> &v, const std::string &c)
{
    std::string::size_type pos1, pos2;
    pos2 = s.find(c);
    pos1 = 0;
    while (std::string::npos != pos2)
    {
        v.push_back(s.substr(pos1, pos2 - pos1));

        pos1 = pos2 + c.size();
        pos2 = s.find(c, pos1);
    }
    if (pos1 != s.length())
        v.push_back(s.substr(pos1));
}

void my_initgroups(string name, int id)
{
    // initgroups()用来从组文件(/etc/group)中依次读取数据
    // 若该组数据的成员中有参数user 时,便将参数group组识别码加入到该进程中
    // 然后额外加入id
    // 需要有效权限为0
    string buffer;
    ifstream in("/etc/group");
    vector<int> need_group;
    while (!in.eof())
    {
        getline(in, buffer);
        vector<string> list;
        SplitString(buffer, list, ":");
        if (list.size() > 0)
        {
            if (list.at(list.size() - 1) == name)
            {
                need_group.push_back(atoi((list.at(list.size() - 2)).c_str()));
            }
        }
    }
    gid_t grouplist[64];
    int len = need_group.size();
    int i;

    for (i = 0; i < len; i++)
    {
        grouplist[i] = need_group[i];
    }
    grouplist[i] = id;
    setgroups(len + 1, grouplist);
}

int main(void)
{
    gid_t grouplist[64];
    my_initgroups("pulse", 1234);
    getgroups(getgroups(0, grouplist), grouplist);
    for (int i = 0; i < getgroups(0, grouplist); i++)
    {
        printf("%d ", grouplist[i]);
    }
    return 0;
}

initgroups函数的作用是将给定的name在/etc/group文件中找到所有的父组,然后将父组的id都记下来,最后加上一个额外的id,替换为当前的组id。我们也是这样来实现的。为了方便拆分字符串,使用SplitString来帮助拆分。运行结果如下:

$ g++ 9-2.cpp
$ sudo ./a.out
29 1234

9-4 当前用户凭证如下:

real = X effective = Y saved = Y

如何执行如下操作?

a)挂起和恢复set-user-ID身份

b)永久放弃set-user-ID身份

由于当前不是特权用户,不能随意切换,所以要受到约束。

获取用户id:

X=getuid()
Y=geteuid()

a)挂起:

setuid(X)

恢复:

setuid(Y)

b) 永久放弃set-user-ID

setreuid(-1,X)

9-5 如果当前用户凭证如下,则要如何执行上面的操作?

real = X effective = 0 saved = 0

当前用户是特权用户。

获取用户id:

X=getuid()
Y=geteuid()

a)挂起:

seteuid(X)

恢复:

seteuid(0)

b)永久放弃权限:

setuid(X)

results matching ""

    No results matching ""