⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cred.c++

📁 好东东。linux下面的文件节点、文件状态的变化监听代码
💻 C++
字号:
//  Copyright (C) 1999-2002 Silicon Graphics, Inc.  All Rights Reserved.////  This program is free software; you can redistribute it and/or modify it//  under the terms of version 2 of the GNU General Public License as//  published by the Free Software Foundation.////  This program is distributed in the hope that it would be useful, but//  WITHOUT ANY WARRANTY; without even the implied warranty of//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any//  license provided herein, whether implied or otherwise, is limited to//  this program in accordance with the express provisions of the GNU//  General Public License.  Patent licenses, if any, provided herein do not//  apply to combinations of this program with other product or programs, or//  any other product whatsoever.  This program is distributed without any//  warranty that the program is delivered free of the rightful claim of any//  third person by way of infringement or the like.  See the GNU General//  Public License for more details.////  You should have received a copy of the GNU General Public License along//  with this program; if not, write the Free Software Foundation, Inc., 59//  Temple Place - Suite 330, Boston MA 02111-1307, USA.#include "Cred.h"#include <assert.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <grp.h>#include <stdlib.h>#include <ctype.h>#include <pwd.h>#include <errno.h>#include "Log.h"#ifdef HAVE_MAC#include <sys/mac.h>#include <t6net.h>#endifstatic gid_t SuperUser_groups[1] = { 0 };const Cred Cred::SuperUser(0, 1, SuperUser_groups, -1);Cred Cred::untrusted;const Cred::Implementation *Cred::Implementation::last = NULL;Cred::Implementation **Cred::impllist;unsigned Cred::nimpl;unsigned Cred::nimpl_alloc;bool Cred::insecure_compat = false;#ifdef HAVE_MACbool Cred::use_mac = true;#endif//  This is used by Listener to create a new Cred for each connection whose//  per-request UIDs will be ignored.  (The uid could either be the untrusted//  uid, or the uid which the client has been authenticated as.)  It's also//  used by Cred::set_untrusted_user() to create the untrusted Cred.Cred::Cred(uid_t u, int sockfd){    unsigned int nAddlGroups = sysconf(_SC_NGROUPS_MAX);    struct passwd *pwd;    gid_t *addlGroups = new gid_t[nAddlGroups];    gid_t primary_group;    if ((pwd = getpwuid(u)) != NULL)    {        primary_group = pwd->pw_gid;#if HAVE_GETGRMEMBER        nAddlGroups = getgrmember(pwd->pw_name, addlGroups, nAddlGroups, 0);        if (nAddlGroups == -1)        {            Log::info("getgrmember(%s, ...) failed: %s",			pwd->pw_name, strerror(errno));            nAddlGroups = 0;        }#else        group *gbp;        unsigned int ii = 0;        setgrent();        while ((ii < nAddlGroups) && ((gbp = getgrent()) != NULL))        {            //  See if our user's name is in the list of group members.            for (int i = 0; gbp->gr_mem[i] != NULL; ++i)            {                if (!strcmp(pwd->pw_name, gbp->gr_mem[i]))                {                    addlGroups[ii++] = gbp->gr_gid;                    break;                }            }        }        endgrent();        nAddlGroups = ii;#endif  //  HAVE_GETGRMEMBER    }    else    {        nAddlGroups = 0;        primary_group = untrusted.is_valid() ? untrusted.gid() : NOGROUP;        Log::info("Warning: uid %i is unknown to this system, so "                  "that user will be given the gid of the untrusted user: %i",                  u, primary_group);                      }    mac_t mac = NULL;#ifdef HAVE_MAC    if ((use_mac) && (sockfd != -1))    {        if(tsix_get_mac(sockfd, &mac) != 0)        {            Log::error("tsix_get_mac failed for client fd %d", sockfd);            exit(1);        }    }#endif    new_impl(u, primary_group, nAddlGroups, addlGroups, mac);    delete [] addlGroups;}//  This is used by TCP_Client to create a new Cred for each request from//  a trusted remote fam.  The MAC label is not handled correctly; the//  remote fam's is being used, rather than the remote client's.Cred::Cred(uid_t u, unsigned int ng, const gid_t *gs, int sockfd){    mac_t mac = NULL;#ifdef HAVE_MAC    if (use_mac) tsix_get_mac(sockfd, &mac); #endif    // The first gid in the group array should be considered the    // primary group id, and the remaining groups are additional    new_impl(u, gs[0], ng-1, gs+1, mac);}//  This is used by Cred::get_cred_for_untrusted_conn() to create a new//  Cred for each unauthenticated connection.  Before the MAC stuff was//  added, we could just use the untrusted Cred, but now each untrusted can//  have their own MAC label.Cred::Cred(int sockfd){#ifdef HAVE_MAC    if (use_mac)    {        mac_t mac = NULL;        if(tsix_get_mac(sockfd, &mac) != 0)        {            //  what to do in this case?  Proceed without a good MAC label?            Log::error("tsix_get_mac failed for client fd %d", sockfd);        }        //  this is broken: needs to test for null untrusted.p        else if (mac_equal(mac, untrusted.p->mac) == 0)	{            new_impl(untrusted.p->myuid, untrusted.p->mygid,                     untrusted.p->nAddlGroups, untrusted.p->AddlGroups, mac);            return;        }	else mac_free(mac);  // because we'll share the Implementation.    }#endif    //  If we're here, either we're not using MAC or the socket's MAC label    //  matches untrusted's, so we want to share untrusted's Implementation.    p = untrusted.p;    if (p != NULL) p->refcount++;}//  This builds an invalid cred which shouldn't be used until it's assigned//  the value of a good cred.  It's used for the uninitialized untrusted cred,//  and for the Creds which are created per-connection by//  Listener::accept_client.Cred::Cred(){    p = NULL;}Cred::Cred(const Cred& that){    p = that.p;    if (p != NULL) p->refcount++;}Cred::~Cred(){    if (p && (!--p->refcount)) drop(p);}Cred&Cred::operator = (const Cred& that){    if (this != &that)    {   if ((p != NULL) && (!--p->refcount))	    drop(p);	p = that.p;	if (p != NULL) p->refcount++;    }    return *this;}voidCred::add(Implementation *np){    if (nimpl >= nimpl_alloc)    {   nimpl_alloc = nimpl_alloc * 3 / 2 + 3;	Implementation **nl = new Implementation *[nimpl_alloc];	for (int i = 0; i < nimpl; i++)	    nl[i] = impllist[i];	delete [] impllist;	impllist = nl;    }    impllist[nimpl++] = np;}voidCred::drop(Implementation *dp){    assert(!dp->refcount);    for (Implementation **pp = impllist, **end = pp + nimpl; pp < end; pp++)	if (*pp == dp)	{   *pp = *--end;	    assert(nimpl);	    --nimpl;	    break;	}    delete dp;    if (!nimpl)    {   delete[] impllist;	impllist = NULL;	nimpl_alloc = 0;    }}voidCred::new_impl(uid_t u, gid_t g, unsigned int ng, const gid_t *gs, mac_t mac){    for (Implementation **pp = impllist, **end = pp + nimpl; pp < end; pp++)	if ((*pp)->equal(u, g, ng, gs, mac))	{   (*pp)->refcount++;	    p = *pp;#ifdef HAVE_MAC            if (mac != NULL) mac_free(mac);#endif	    return;	}    p = new Implementation(u, g, ng, gs, mac);    add(p);}voidCred::set_untrusted_user(const char *name){    //  The only time this should get called is at startup, when we're    //  handling command-line or config-file options, and before any    //  requests are accepted.    assert(!untrusted.is_valid());    //  The untrusted user is never used if we're running in    //  insecure_compat mode.    if (insecure_compat) return;    //  First see if we were passed a uid.    const char *p = name;    while (isdigit(*p)) ++p;    if((*p == '\0') && (p != name))  // need at least one character!    {        uid_t uid = atoi(name);        struct passwd *pwd = getpwuid(uid);        if(pwd == NULL)        {            Log::error("Fatal misconfiguration: attempted to use unknown uid "                       "\"%i\" for untrusted-user", uid);            exit(1);        }        Cred tmpcred(uid, -1);        untrusted = tmpcred;        Log::debug("Setting untrusted-user to \"%s\" (uid: %d, gid: %d)",                   pwd->pw_name, pwd->pw_uid, pwd->pw_gid);        return;    }    //  Looks like we were passed a user name.    struct passwd *pwd = getpwnam(name);    if(pwd == NULL)    {        Log::error("Fatal misconfiguration: attempted to use unknown user "                   "name \"%s\" for untrusted-user", name);        exit(1);    }    Log::debug("Setting untrusted-user to \"%s\" (uid: %d, gid: %d)",               name, pwd->pw_uid, pwd->pw_gid);    Cred tmpcred(pwd->pw_uid, -1);    untrusted = tmpcred;}CredCred::get_cred_for_untrusted_conn(int sockfd){    //  An invalid Cred on a connection means we'll trust the Creds supplied    //  by the connection.  In the case where insecure_compat is enabled, we    //  always want to return an invalid Cred.  As it happens, untrusted is    //  always invalid when insecure_compat is enabled, so we just use it.    //  If insecure compat isn't enabled, we want to return a valid untrusted    //  Cred.    assert(untrusted.is_valid() || insecure_compat);    return insecure_compat ? untrusted : Cred(sockfd);}voidCred::disable_mac(){#ifdef HAVE_MAC    use_mac = false;    Log::audit(true, "running with MAC disabled, so all client requests will "                     "use fam's MAC label.");#endif}voidCred::enable_insecure_compat(){    insecure_compat = true;    Log::audit(true, "running in insecure compatibility mode");    Log::info("running in insecure compatibility mode");}///////////////////////////////////////////////////////////////////////////////Cred::Implementation::Implementation(uid_t u, gid_t g,                                     unsigned int ng, const gid_t *gs,                                     mac_t m)    : refcount(1), myuid(u), mygid(g), nAddlGroups(ng){#ifdef HAVE_MAC    mac = NULL;    if (use_mac) mac = m;    else if (m != NULL) mac_free(m);#endif    AddlGroups = new gid_t[ng];    for (int i = 0; i < nAddlGroups; i++)	AddlGroups[i] = gs[i];    if (nAddlGroups == 0) {        addlGroupsStr = new char[1];        *addlGroupsStr = '\0';    }    else {        // The format is: <number of addl groups> <gid1> <gid2> ... <gidn>                // Assume that the each num and accompanying space (or null        // character in the case of the last one) will be <= 11 chars.        addlGroupsStr = new char[11*(nAddlGroups + 1)];        char * p = addlGroupsStr;        p += snprintf(p, 10, "%d", nAddlGroups);        for (int i = 0; i < nAddlGroups; i++)        {            p += snprintf(p, 11, " %d", AddlGroups[i]);        }    }}Cred::Implementation::~Implementation(){    if (this == last)	SuperUser.become_user();    delete [] AddlGroups;    delete [] addlGroupsStr;#ifdef HAVE_MAC    if (mac != NULL) mac_free(mac);#endif}boolCred::Implementation::equal(uid_t u, gid_t g, unsigned int ng,                            const gid_t *gs, mac_t mac) const{    if ((u != myuid) || (g != mygid)) {        return false;    }#ifdef HAVE_MAC    if ((use_mac) && (mac_equal(this->mac, mac) == 0)) return -1;#endif    return addl_groups_equal(ng, gs);}boolCred::Implementation::addl_groups_equal(unsigned int ng, const gid_t *gs) const{    if (ng != nAddlGroups) {        return false;    }    for (int i = 0; i < nAddlGroups; i++)	if (AddlGroups[i] != gs[i])	    return false;    return true;}// This function returns a string representation of the additional// groups, as required by ServerConnection::send_monitor().const char *Cred::Implementation::getAddlGroupsString() const {    return addlGroupsStr;}voidCred::Implementation::become_user() const{    // If we're becoming the same user we currently are, then we can    // just skip everything.    if (this == last)	return;    uid_t current_uid = last ? last->myuid : 0;    if (current_uid != 0) {        /* Temporarily set the effective uid to root's uid         * so that we have permission to call setgroups, etc.         * This assumes, of course, that we were started as root,         * so that we have permission to do this.         */        Log::debug("Setting euid to 0");        if (seteuid(0) != 0)        {            Log::perror("failed to set 0 uid");            exit(1);        }    }    // We need to set the primary group and additional groups before    // setting our euid because non-root users don't have permission    // to change the groups.    if (!last || !addl_groups_equal(last->nAddlGroups, last->AddlGroups)) {	if (setgroups(nAddlGroups, AddlGroups) != 0) {            Log::perror("failed to set groups");            exit(1);	} else if (Log::get_level() == Log::DEBUG) {            if (nAddlGroups == 0) {                Log::debug("Setting groups to: (none)");            } else {                // The groupStr variable is almost what we want, but                // it has the number of groups prepended.  So just                // skip over that.                char * p = strchr(addlGroupsStr, ' ');                Log::debug("Setting groups to: %s", p+1);            }        }    } else {        Log::debug("Skipping setting groups, because they're already correct");    }        if (!last || (mygid != last->mygid)) {        if (setegid(mygid)) {            Log::perror("failed to set gid %d", mygid);            exit(1);        } else {            Log::debug("Setting egid to %i", mygid);        }    } else {        Log::debug("Skipping setting egid, because it's already correct");    }            if (myuid != 0) { // We can skip this if we're becoming root, as                      // we either entered this function as root, or                      // set our euid to root above        if (seteuid(myuid)) {            Log::perror("failed to set uid %d", myuid);            exit(1);        } else {            Log::debug("Setting euid to %i", myuid);        }    } else {        if (current_uid != 0) {            // We already logged a message above        } else {            Log::debug("Skipping setting euid, because it's already 0");        }    }    #ifdef HAVE_MAC    if (use_mac)    {        if (mac_set_proc(mac) != 0)        {            Log::perror("become_user() failed to set MAC label for uid %d", myuid);        }    }#endif    last = this;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -