[BACK]Return to Cred.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/Cred.c++, Revision 1.1.1.1

1.1       trev        1: //  Copyright (C) 1999-2002 Silicon Graphics, Inc.  All Rights Reserved.
                      2: //
                      3: //  This program is free software; you can redistribute it and/or modify it
                      4: //  under the terms of version 2 of the GNU General Public License as
                      5: //  published by the Free Software Foundation.
                      6: //
                      7: //  This program is distributed in the hope that it would be useful, but
                      8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
                      9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
                     10: //  license provided herein, whether implied or otherwise, is limited to
                     11: //  this program in accordance with the express provisions of the GNU
                     12: //  General Public License.  Patent licenses, if any, provided herein do not
                     13: //  apply to combinations of this program with other product or programs, or
                     14: //  any other product whatsoever.  This program is distributed without any
                     15: //  warranty that the program is delivered free of the rightful claim of any
                     16: //  third person by way of infringement or the like.  See the GNU General
                     17: //  Public License for more details.
                     18: //
                     19: //  You should have received a copy of the GNU General Public License along
                     20: //  with this program; if not, write the Free Software Foundation, Inc., 59
                     21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
                     22:
                     23: #include "Cred.h"
                     24:
                     25: #include <assert.h>
                     26: #include <stdio.h>
                     27: #include <string.h>
                     28: #include <unistd.h>
                     29: #include <grp.h>
                     30: #include <stdlib.h>
                     31: #include <ctype.h>
                     32: #include <pwd.h>
                     33: #include <errno.h>
                     34:
                     35: #include "Log.h"
                     36: #ifdef HAVE_MAC
                     37: #include <sys/mac.h>
                     38: #include <t6net.h>
                     39: #endif
                     40:
                     41: static gid_t SuperUser_groups[1] = { 0 };
                     42: const Cred Cred::SuperUser(0, 1, SuperUser_groups, -1);
                     43: Cred Cred::untrusted;
                     44: const Cred::Implementation *Cred::Implementation::last = NULL;
                     45: Cred::Implementation **Cred::impllist;
                     46: unsigned Cred::nimpl;
                     47: unsigned Cred::nimpl_alloc;
                     48: bool Cred::insecure_compat = false;
                     49: #ifdef HAVE_MAC
                     50: bool Cred::use_mac = true;
                     51: #endif
                     52:
                     53: //  This is used by Listener to create a new Cred for each connection whose
                     54: //  per-request UIDs will be ignored.  (The uid could either be the untrusted
                     55: //  uid, or the uid which the client has been authenticated as.)  It's also
                     56: //  used by Cred::set_untrusted_user() to create the untrusted Cred.
                     57: Cred::Cred(uid_t u, int sockfd)
                     58: {
                     59:     unsigned int nAddlGroups = sysconf(_SC_NGROUPS_MAX);
                     60:     struct passwd *pwd;
                     61:     gid_t *addlGroups = new gid_t[nAddlGroups];
                     62:     gid_t primary_group;
                     63:     if ((pwd = getpwuid(u)) != NULL)
                     64:     {
                     65:         primary_group = pwd->pw_gid;
                     66: #ifdef HAVE_GETGRMEMBER
                     67:         nAddlGroups = getgrmember(pwd->pw_name, addlGroups, nAddlGroups, 0);
                     68:         if (nAddlGroups == -1)
                     69:         {
                     70:             Log::info("getgrmember(%s, ...) failed: %s",
                     71: 			pwd->pw_name, strerror(errno));
                     72:             nAddlGroups = 0;
                     73:         }
                     74: #else
                     75:         group *gbp;
                     76:         unsigned int ii = 0;
                     77:         setgrent();
                     78:         while ((ii < nAddlGroups) && ((gbp = getgrent()) != NULL))
                     79:         {
                     80:             //  See if our user's name is in the list of group members.
                     81:             for (int i = 0; gbp->gr_mem[i] != NULL; ++i)
                     82:             {
                     83:                 if (!strcmp(pwd->pw_name, gbp->gr_mem[i]))
                     84:                 {
                     85:                     addlGroups[ii++] = gbp->gr_gid;
                     86:                     break;
                     87:                 }
                     88:             }
                     89:         }
                     90:         endgrent();
                     91:         nAddlGroups = ii;
                     92: #endif
                     93:     }
                     94:     else
                     95:     {
                     96:         nAddlGroups = 0;
                     97: #ifdef NOGROUP
                     98:         primary_group = untrusted.is_valid() ? untrusted.gid() : (gid_t) NOGROUP;
                     99: #else
                    100:         primary_group = untrusted.is_valid() ? untrusted.gid() : (gid_t) GID_NOBODY;
                    101: #endif
                    102:         Log::info("Warning: uid %i is unknown to this system, so "
                    103:                   "that user will be given the gid of the untrusted user: %i",
                    104:                   u, primary_group);
                    105:
                    106:     }
                    107:     mac_t mac = NULL;
                    108: #ifdef HAVE_MAC
                    109:     if ((use_mac) && (sockfd != -1))
                    110:     {
                    111:         if(tsix_get_mac(sockfd, &mac) != 0)
                    112:         {
                    113:             Log::error("tsix_get_mac failed for client fd %d", sockfd);
                    114:             exit(1);
                    115:         }
                    116:     }
                    117: #endif
                    118:     new_impl(u, primary_group, nAddlGroups, addlGroups, mac);
                    119:     delete [] addlGroups;
                    120: }
                    121:
                    122: //  This is used by TCP_Client to create a new Cred for each request from
                    123: //  a trusted remote fam.  The MAC label is not handled correctly; the
                    124: //  remote fam's is being used, rather than the remote client's.
                    125: Cred::Cred(uid_t u, unsigned int ng, const gid_t *gs, int sockfd)
                    126: {
                    127:     mac_t mac = NULL;
                    128: #ifdef HAVE_MAC
                    129:     if (use_mac) tsix_get_mac(sockfd, &mac);
                    130: #endif
                    131:     // The first gid in the group array should be considered the
                    132:     // primary group id, and the remaining groups are additional
                    133:     new_impl(u, gs[0], ng-1, gs+1, mac);
                    134: }
                    135:
                    136: //  This is used by Cred::get_cred_for_untrusted_conn() to create a new
                    137: //  Cred for each unauthenticated connection.  Before the MAC stuff was
                    138: //  added, we could just use the untrusted Cred, but now each untrusted can
                    139: //  have their own MAC label.
                    140: Cred::Cred(int sockfd)
                    141: {
                    142: #ifdef HAVE_MAC
                    143:     if (use_mac)
                    144:     {
                    145:         mac_t mac = NULL;
                    146:         if(tsix_get_mac(sockfd, &mac) != 0)
                    147:         {
                    148:             //  what to do in this case?  Proceed without a good MAC label?
                    149:             Log::error("tsix_get_mac failed for client fd %d", sockfd);
                    150:         }
                    151:         //  this is broken: needs to test for null untrusted.p
                    152:         else if (mac_equal(mac, untrusted.p->mac) == 0)
                    153: 	{
                    154:             new_impl(untrusted.p->myuid, untrusted.p->mygid,
                    155:                      untrusted.p->nAddlGroups, untrusted.p->AddlGroups, mac);
                    156:             return;
                    157:         }
                    158: 	else mac_free(mac);  // because we'll share the Implementation.
                    159:     }
                    160: #endif
                    161:     //  If we're here, either we're not using MAC or the socket's MAC label
                    162:     //  matches untrusted's, so we want to share untrusted's Implementation.
                    163:     p = untrusted.p;
                    164:     if (p != NULL) p->refcount++;
                    165: }
                    166:
                    167: //  This builds an invalid cred which shouldn't be used until it's assigned
                    168: //  the value of a good cred.  It's used for the uninitialized untrusted cred,
                    169: //  and for the Creds which are created per-connection by
                    170: //  Listener::accept_client.
                    171: Cred::Cred()
                    172: {
                    173:     p = NULL;
                    174: }
                    175:
                    176: Cred::Cred(const Cred& that)
                    177: {
                    178:     p = that.p;
                    179:     if (p != NULL) p->refcount++;
                    180: }
                    181:
                    182: Cred::~Cred()
                    183: {
                    184:     if (p && (!--p->refcount)) drop(p);
                    185: }
                    186:
                    187: Cred&
                    188: Cred::operator = (const Cred& that)
                    189: {
                    190:     if (this != &that)
                    191:     {   if ((p != NULL) && (!--p->refcount))
                    192: 	    drop(p);
                    193: 	p = that.p;
                    194: 	if (p != NULL) p->refcount++;
                    195:     }
                    196:     return *this;
                    197: }
                    198:
                    199: void
                    200: Cred::add(Implementation *np)
                    201: {
                    202:     if (nimpl >= nimpl_alloc)
                    203:     {   nimpl_alloc = nimpl_alloc * 3 / 2 + 3;
                    204: 	Implementation **nl = new Implementation *[nimpl_alloc];
                    205: 	for (int i = 0; i < nimpl; i++)
                    206: 	    nl[i] = impllist[i];
                    207: 	delete [] impllist;
                    208: 	impllist = nl;
                    209:     }
                    210:     impllist[nimpl++] = np;
                    211: }
                    212:
                    213: void
                    214: Cred::drop(Implementation *dp)
                    215: {
                    216:     assert(!dp->refcount);
                    217:     for (Implementation **pp = impllist, **end = pp + nimpl; pp < end; pp++)
                    218: 	if (*pp == dp)
                    219: 	{   *pp = *--end;
                    220: 	    assert(nimpl);
                    221: 	    --nimpl;
                    222: 	    break;
                    223: 	}
                    224:     delete dp;
                    225:
                    226:     if (!nimpl)
                    227:     {   delete[] impllist;
                    228: 	impllist = NULL;
                    229: 	nimpl_alloc = 0;
                    230:     }
                    231: }
                    232:
                    233: void
                    234: Cred::new_impl(uid_t u, gid_t g, unsigned int ng, const gid_t *gs, mac_t mac)
                    235: {
                    236:     for (Implementation **pp = impllist, **end = pp + nimpl; pp < end; pp++)
                    237: 	if ((*pp)->equal(u, g, ng, gs, mac))
                    238: 	{   (*pp)->refcount++;
                    239: 	    p = *pp;
                    240: #ifdef HAVE_MAC
                    241:             if (mac != NULL) mac_free(mac);
                    242: #endif
                    243: 	    return;
                    244: 	}
                    245:
                    246:     p = new Implementation(u, g, ng, gs, mac);
                    247:     add(p);
                    248: }
                    249:
                    250: void
                    251: Cred::set_untrusted_user(const char *name)
                    252: {
                    253:     //  The only time this should get called is at startup, when we're
                    254:     //  handling command-line or config-file options, and before any
                    255:     //  requests are accepted.
                    256:     assert(!untrusted.is_valid());
                    257:
                    258:     //  The untrusted user is never used if we're running in
                    259:     //  insecure_compat mode.
                    260:     if (insecure_compat) return;
                    261:
                    262:     //  First see if we were passed a uid.
                    263:     const char *p = name;
                    264:     while (isdigit(*p)) ++p;
                    265:     if((*p == '\0') && (p != name))  // need at least one character!
                    266:     {
                    267:         uid_t uid = atoi(name);
                    268:         struct passwd *pwd = getpwuid(uid);
                    269:         if(pwd == NULL)
                    270:         {
                    271:             Log::error("Fatal misconfiguration: attempted to use unknown uid "
                    272:                        "\"%i\" for untrusted-user", uid);
                    273:             exit(1);
                    274:         }
                    275:         Cred tmpcred(uid, -1);
                    276:         untrusted = tmpcred;
                    277:         Log::debug("Setting untrusted-user to \"%s\" (uid: %d, gid: %d)",
                    278:                    pwd->pw_name, pwd->pw_uid, pwd->pw_gid);
                    279:         return;
                    280:     }
                    281:
                    282:     //  Looks like we were passed a user name.
                    283:     struct passwd *pwd = getpwnam(name);
                    284:     if(pwd == NULL)
                    285:     {
                    286:         Log::error("Fatal misconfiguration: attempted to use unknown user "
                    287:                    "name \"%s\" for untrusted-user", name);
                    288:         exit(1);
                    289:     }
                    290:     Log::debug("Setting untrusted-user to \"%s\" (uid: %d, gid: %d)",
                    291:                name, pwd->pw_uid, pwd->pw_gid);
                    292:     Cred tmpcred(pwd->pw_uid, -1);
                    293:     untrusted = tmpcred;
                    294: }
                    295:
                    296: Cred
                    297: Cred::get_cred_for_untrusted_conn(int sockfd)
                    298: {
                    299:     //  An invalid Cred on a connection means we'll trust the Creds supplied
                    300:     //  by the connection.  In the case where insecure_compat is enabled, we
                    301:     //  always want to return an invalid Cred.  As it happens, untrusted is
                    302:     //  always invalid when insecure_compat is enabled, so we just use it.
                    303:     //  If insecure compat isn't enabled, we want to return a valid untrusted
                    304:     //  Cred.
                    305:     assert(untrusted.is_valid() || insecure_compat);
                    306:     return insecure_compat ? untrusted : Cred(sockfd);
                    307: }
                    308:
                    309: void
                    310: Cred::disable_mac()
                    311: {
                    312: #ifdef HAVE_MAC
                    313:     use_mac = false;
                    314:     Log::audit(true, "running with MAC disabled, so all client requests will "
                    315:                      "use fam's MAC label.");
                    316: #endif
                    317: }
                    318:
                    319: void
                    320: Cred::enable_insecure_compat()
                    321: {
                    322:     insecure_compat = true;
                    323:     Log::audit(true, "running in insecure compatibility mode");
                    324:     Log::info("running in insecure compatibility mode");
                    325: }
                    326:
                    327: ///////////////////////////////////////////////////////////////////////////////
                    328:
                    329: Cred::Implementation::Implementation(uid_t u, gid_t g,
                    330:                                      unsigned int ng, const gid_t *gs,
                    331:                                      mac_t m)
                    332:     : refcount(1), myuid(u), mygid(g), nAddlGroups(ng)
                    333: {
                    334: #ifdef HAVE_MAC
                    335:     mac = NULL;
                    336:     if (use_mac) mac = m;
                    337:     else if (m != NULL) mac_free(m);
                    338: #endif
                    339:     AddlGroups = new gid_t[ng];
                    340:
                    341:     for (int i = 0; i < nAddlGroups; i++)
                    342: 	AddlGroups[i] = gs[i];
                    343:
                    344:     if (nAddlGroups == 0) {
                    345:         addlGroupsStr = new char[1];
                    346:         *addlGroupsStr = '\0';
                    347:     }
                    348:     else {
                    349:         // The format is: <number of addl groups> <gid1> <gid2> ... <gidn>
                    350:
                    351:         // Assume that the each num and accompanying space (or null
                    352:         // character in the case of the last one) will be <= 11 chars.
                    353:         addlGroupsStr = new char[11*(nAddlGroups + 1)];
                    354:         char * p = addlGroupsStr;
                    355:         p += snprintf(p, 10, "%d", nAddlGroups);
                    356:         for (int i = 0; i < nAddlGroups; i++)
                    357:         {
                    358:             p += snprintf(p, 11, " %d", AddlGroups[i]);
                    359:         }
                    360:     }
                    361: }
                    362:
                    363: Cred::Implementation::~Implementation()
                    364: {
                    365:     if (this == last)
                    366: 	SuperUser.become_user();
                    367:     delete [] AddlGroups;
                    368:     delete [] addlGroupsStr;
                    369: #ifdef HAVE_MAC
                    370:     if (mac != NULL) mac_free(mac);
                    371: #endif
                    372: }
                    373:
                    374: bool
                    375: Cred::Implementation::equal(uid_t u, gid_t g, unsigned int ng,
                    376:                             const gid_t *gs, mac_t mac) const
                    377: {
                    378:     if ((u != myuid) || (g != mygid)) {
                    379:         return false;
                    380:     }
                    381: #ifdef HAVE_MAC
                    382:     if ((use_mac) && (mac_equal(this->mac, mac) == 0)) return -1;
                    383: #endif
                    384:     return addl_groups_equal(ng, gs);
                    385: }
                    386:
                    387: bool
                    388: Cred::Implementation::addl_groups_equal(unsigned int ng, const gid_t *gs) const
                    389: {
                    390:     if (ng != nAddlGroups) {
                    391:         return false;
                    392:     }
                    393:     for (int i = 0; i < nAddlGroups; i++)
                    394: 	if (AddlGroups[i] != gs[i])
                    395: 	    return false;
                    396:     return true;
                    397: }
                    398:
                    399: // This function returns a string representation of the additional
                    400: // groups, as required by ServerConnection::send_monitor().
                    401: const char *
                    402: Cred::Implementation::getAddlGroupsString() const {
                    403:     return addlGroupsStr;
                    404: }
                    405:
                    406: void
                    407: Cred::Implementation::become_user() const
                    408: {
                    409:     // If we're becoming the same user we currently are, then we can
                    410:     // just skip everything.
                    411:     if (this == last)
                    412: 	return;
                    413:
                    414:     uid_t current_uid = last ? last->myuid : 0;
                    415:     if (current_uid != 0) {
                    416:         /* Temporarily set the effective uid to root's uid
                    417:          * so that we have permission to call setgroups, etc.
                    418:          * This assumes, of course, that we were started as root,
                    419:          * so that we have permission to do this.
                    420:          */
                    421:         Log::debug("Setting euid to 0");
                    422:         if (seteuid(0) != 0)
                    423:         {
                    424:             Log::perror("failed to set 0 uid");
                    425:             exit(1);
                    426:         }
                    427:     }
                    428:
                    429:     // We need to set the primary group and additional groups before
                    430:     // setting our euid because non-root users don't have permission
                    431:     // to change the groups.
                    432:     if (!last || !addl_groups_equal(last->nAddlGroups, last->AddlGroups)) {
                    433: 	if (setgroups(nAddlGroups, AddlGroups) != 0) {
                    434:             Log::perror("failed to set groups");
                    435:             exit(1);
                    436: 	} else if (Log::get_level() == Log::DEBUG) {
                    437:             if (nAddlGroups == 0) {
                    438:                 Log::debug("Setting groups to: (none)");
                    439:             } else {
                    440:                 // The groupStr variable is almost what we want, but
                    441:                 // it has the number of groups prepended.  So just
                    442:                 // skip over that.
                    443:                 char * p = strchr(addlGroupsStr, ' ');
                    444:                 Log::debug("Setting groups to: %s", p+1);
                    445:             }
                    446:         }
                    447:     } else {
                    448:         Log::debug("Skipping setting groups, because they're already correct");
                    449:     }
                    450:
                    451:     if (!last || (mygid != last->mygid)) {
                    452:         if (setegid(mygid)) {
                    453:             Log::perror("failed to set gid %d", mygid);
                    454:             exit(1);
                    455:         } else {
                    456:             Log::debug("Setting egid to %i", mygid);
                    457:         }
                    458:     } else {
                    459:         Log::debug("Skipping setting egid, because it's already correct");
                    460:     }
                    461:
                    462:
                    463:
                    464:     if (myuid != 0) { // We can skip this if we're becoming root, as
                    465:                       // we either entered this function as root, or
                    466:                       // set our euid to root above
                    467:         if (seteuid(myuid)) {
                    468:             Log::perror("failed to set uid %d", myuid);
                    469:             exit(1);
                    470:         } else {
                    471:             Log::debug("Setting euid to %i", myuid);
                    472:         }
                    473:     } else {
                    474:         if (current_uid != 0) {
                    475:             // We already logged a message above
                    476:         } else {
                    477:             Log::debug("Skipping setting euid, because it's already 0");
                    478:         }
                    479:     }
                    480:
                    481:
                    482: #ifdef HAVE_MAC
                    483:     if (use_mac)
                    484:     {
                    485:         if (mac_set_proc(mac) != 0)
                    486:         {
                    487:             Log::perror("become_user() failed to set MAC label for uid %d", myuid);
                    488:         }
                    489:     }
                    490: #endif
                    491:     last = this;
                    492: }
                    493:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>