XrdSysPriv.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                     X r d S y s P r i v . c c                              */
00004 /*                                                                            */
00005 /* (c) 2006 G. Ganis (CERN)                                                   */
00006 /*     All Rights Reserved. See XrdInfo.cc for complete License Terms         */
00007 /******************************************************************************/
00008 // $Id: XrdSysPriv.cc 30949 2009-11-02 16:37:58Z ganis $
00009 
00010 const char *XrdSysPrivCVSID = "$Id: XrdSysPriv.cc 30949 2009-11-02 16:37:58Z ganis $";
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // XrdSysPriv                                                           //
00015 //                                                                      //
00016 // Author: G. Ganis, CERN, 2006                                         //
00017 //                                                                      //
00018 // Implementation of a privileges handling API following the paper      //
00019 //   "Setuid Demystified" by H.Chen, D.Wagner, D.Dean                   //
00020 // also quoted in "Secure programming Cookbook" by J.Viega & M.Messier. //
00021 //                                                                      //
00022 //////////////////////////////////////////////////////////////////////////
00023 
00024 #include "XrdSys/XrdSysPriv.hh"
00025 
00026 #if !defined(WINDOWS)
00027 #include <stdio.h>
00028 #include "XrdSys/XrdSysHeaders.hh"
00029 #include <unistd.h>
00030 #include <pwd.h>
00031 #include <errno.h>
00032 
00033 #define NOUC ((uid_t)(-1))
00034 #define NOGC ((gid_t)(-1))
00035 #define XSPERR(x) ((x == 0) ? -1 : -x)
00036 
00037 // Some machine specific stuff
00038 #if defined(__sgi) && !defined(__GNUG__) && (SGI_REL<62)
00039 extern "C" {
00040    int seteuid(int euid);
00041    int setegid(int egid);
00042    int geteuid();
00043    int getegid();
00044 }
00045 #endif
00046 
00047 #if defined(_AIX)
00048 extern "C" {
00049    int seteuid(uid_t euid);
00050    int setegid(gid_t egid);
00051    uid_t geteuid();
00052    gid_t getegid();
00053 }
00054 #endif
00055 
00056 #if !defined(HAVE_SETRESUID)
00057 static int setresgid(gid_t r, gid_t e, gid_t)
00058 {
00059    if (r != NOGC && setgid(r) == -1)
00060       return XSPERR(errno);
00061    return ((e != NOGC) ? setegid(e) : 0);
00062 }
00063 
00064 static int setresuid(uid_t r, uid_t e, uid_t)
00065 {
00066    if (r != NOUC && setuid(r) == -1)
00067       return XSPERR(errno);
00068    return ((e != NOUC) ? seteuid(e) : 0);
00069 }
00070 
00071 static int getresgid(gid_t *r, gid_t *e, gid_t *)
00072 {
00073   *r = getgid();
00074   *e = getegid();
00075   return 0;
00076 }
00077 
00078 static int getresuid(uid_t *r, uid_t *e, uid_t *)
00079 {
00080   *r = getuid();
00081   *e = geteuid();
00082   return 0;
00083 }
00084 
00085 #else
00086 #if (defined(__linux__) || \
00087     (defined(__CYGWIN__) && defined(__GNUC__))) && !defined(linux)
00088 #   define linux
00089 #endif
00090 #if defined(linux) && !defined(HAVE_SETRESUID)
00091 extern "C" {
00092    int setresgid(gid_t r, gid_t e, gid_t s);
00093    int setresuid(uid_t r, uid_t e, uid_t s);
00094    int getresgid(gid_t *r, gid_t *e, gid_t *s);
00095    int getresuid(uid_t *r, uid_t *e, uid_t *s);
00096 }
00097 #endif
00098 #endif
00099 #endif // not WINDOWS
00100 
00101 bool XrdSysPriv::fDebug = 0; // debug switch
00102 
00103 // Gloval mutex
00104 XrdSysRecMutex XrdSysPriv::fgMutex;
00105 
00106 //______________________________________________________________________________
00107 int XrdSysPriv::Restore(bool saved)
00108 {
00109    // Restore the 'saved' (saved = TRUE) or 'real' entity as effective.
00110    // Return 0 on success, < 0 (== -errno) if any error occurs.
00111 
00112 #if !defined(WINDOWS)
00113    // Get the UIDs
00114    uid_t ruid = 0, euid = 0, suid = 0;
00115    if (getresuid(&ruid, &euid, &suid) != 0)
00116       return XSPERR(errno);
00117 
00118    // Set the wanted value
00119    uid_t uid = saved ? suid : ruid;
00120 
00121    // Act only if a change is needed
00122    if (euid != uid) {
00123 
00124       // Set uid as effective
00125       if (setresuid(NOUC, uid, NOUC) != 0)
00126          return XSPERR(errno);
00127 
00128       // Make sure the new effective UID is the one wanted
00129       if (geteuid() != uid)
00130          return XSPERR(errno);
00131    }
00132 
00133    // Get the GIDs
00134    uid_t rgid = 0, egid = 0, sgid = 0;
00135    if (getresgid(&rgid, &egid, &sgid) != 0)
00136       return XSPERR(errno);
00137 
00138    // Set the wanted value
00139    gid_t gid = saved ? sgid : rgid;
00140 
00141    // Act only if a change is needed
00142    if (egid != gid) {
00143 
00144       // Set newuid as effective, saving the current effective GID
00145       if (setresgid(NOGC, gid, NOGC) != 0)
00146          return XSPERR(errno);
00147 
00148       // Make sure the new effective GID is the one wanted
00149       if (getegid() != gid)
00150          return XSPERR(errno);
00151    }
00152 
00153 #endif
00154    // Done
00155    return 0;
00156 }
00157 
00158 //______________________________________________________________________________
00159 int XrdSysPriv::ChangeTo(uid_t newuid, gid_t newgid)
00160 {
00161    // Change effective to entity newuid. Current entity is saved.
00162    // Real entity is not touched. Use RestoreSaved to go back to
00163    // previous settings.
00164    // Return 0 on success, < 0 (== -errno) if any error occurs.
00165 
00166 #if !defined(WINDOWS)
00167    // Current UGID 
00168    uid_t oeuid = geteuid();
00169    gid_t oegid = getegid();
00170 
00171    // Restore privileges, if needed
00172    if (oeuid && XrdSysPriv::Restore(0) != 0)
00173       return XSPERR(errno);
00174 
00175    // Act only if a change is needed
00176    if (newgid != oegid) {
00177 
00178       // Set newgid as effective, saving the current effective GID
00179       if (setresgid(NOGC, newgid, oegid) != 0)
00180          return XSPERR(errno);
00181 
00182       // Get the GIDs
00183       uid_t rgid = 0, egid = 0, sgid = 0;
00184       if (getresgid(&rgid, &egid, &sgid) != 0)
00185          return XSPERR(errno);
00186 
00187       // Make sure the new effective GID is the one wanted
00188       if (egid != newgid)
00189          return XSPERR(errno);
00190    }
00191 
00192    // Act only if a change is needed
00193    if (newuid != oeuid) {
00194 
00195       // Set newuid as effective, saving the current effective UID
00196       if (setresuid(NOUC, newuid, oeuid) != 0)
00197          return XSPERR(errno);
00198 
00199       // Get the UIDs
00200       uid_t ruid = 0, euid = 0, suid = 0;
00201       if (getresuid(&ruid, &euid, &suid) != 0)
00202          return XSPERR(errno);
00203 
00204       // Make sure the new effective UID is the one wanted
00205       if (euid != newuid)
00206          return XSPERR(errno);
00207    }
00208 
00209 #endif
00210    // Done
00211    return 0;
00212 }
00213 
00214 //______________________________________________________________________________
00215 int XrdSysPriv::ChangePerm(uid_t newuid, gid_t newgid)
00216 {
00217    // Change permanently to entity newuid. Requires super-userprivileges.
00218    // Provides a way to drop permanently su privileges.
00219    // Return 0 on success, < 0 (== -errno) if any error occurs.
00220 
00221    // Atomic action
00222    XrdSysPriv::fgMutex.Lock();
00223 #if !defined(WINDOWS)
00224    // Get UIDs
00225    uid_t cruid = 0, ceuid = 0, csuid = 0;
00226    if (getresuid(&cruid, &ceuid, &csuid) != 0) {
00227       XrdSysPriv::fgMutex.UnLock();
00228       return XSPERR(errno);
00229    }
00230 
00231    // Get GIDs
00232    uid_t crgid = 0, cegid = 0, csgid = 0;
00233    if (getresgid(&crgid, &cegid, &csgid) != 0) {
00234       XrdSysPriv::fgMutex.UnLock();
00235       return XSPERR(errno);
00236    }
00237    // Restore privileges, if needed
00238    if (ceuid && XrdSysPriv::Restore(0) != 0) {
00239       XrdSysPriv::fgMutex.UnLock();
00240       return XSPERR(errno);
00241    }
00242    // Act only if needed
00243    if (newgid != cegid || newgid != crgid) {
00244 
00245       // Set newgid as GID, all levels
00246       if (setresgid(newgid, newgid, newgid) != 0) {
00247          XrdSysPriv::fgMutex.UnLock();
00248          return XSPERR(errno);
00249       }
00250       // Get GIDs
00251       uid_t rgid = 0, egid = 0, sgid = 0;
00252       if (getresgid(&rgid, &egid, &sgid) != 0) {
00253          XrdSysPriv::fgMutex.UnLock();
00254          return XSPERR(errno);
00255       }
00256       // Make sure the new GIDs are all equal to the one asked
00257       if (rgid != newgid || egid != newgid) {
00258          XrdSysPriv::fgMutex.UnLock();
00259          return XSPERR(errno);
00260       }
00261    }
00262 
00263    // Act only if needed
00264    if (newuid != ceuid || newuid != cruid) {
00265 
00266       // Set newuid as UID, all levels
00267       if (setresuid(newuid, newuid, newuid) != 0) {
00268          XrdSysPriv::fgMutex.UnLock();
00269          return XSPERR(errno);
00270       }
00271       // Get UIDs
00272       uid_t ruid = 0, euid = 0, suid = 0;
00273       if (getresuid(&ruid, &euid, &suid) != 0) {
00274          XrdSysPriv::fgMutex.UnLock();
00275          return XSPERR(errno);
00276       }
00277       // Make sure the new UIDs are all equal to the one asked 
00278       if (ruid != newuid || euid != newuid) {
00279          XrdSysPriv::fgMutex.UnLock();
00280          return XSPERR(errno);
00281       }
00282    }
00283 #endif
00284    // Release the mutex
00285    XrdSysPriv::fgMutex.UnLock();
00286 
00287    // Done
00288    return 0;
00289 }
00290 
00291 //______________________________________________________________________________
00292 void XrdSysPriv::DumpUGID(const char *msg)
00293 {
00294    // Dump current entity
00295 
00296 #if !defined(WINDOWS)
00297    XrdSysPriv::fgMutex.Lock();
00298    // Get the UIDs
00299    uid_t ruid = 0, euid = 0, suid = 0;
00300    if (getresuid(&ruid, &euid, &suid) != 0)
00301       return;
00302 
00303    // Get the GIDs
00304    uid_t rgid = 0, egid = 0, sgid = 0;
00305    if (getresgid(&rgid, &egid, &sgid) != 0)
00306       return;
00307 
00308    cout << "XrdSysPriv: "  << endl; 
00309    cout << "XrdSysPriv: dump values: " << (msg ? msg : "") << endl; 
00310    cout << "XrdSysPriv: "  << endl; 
00311    cout << "XrdSysPriv: real       = (" << ruid <<","<< rgid <<")" << endl; 
00312    cout << "XrdSysPriv: effective  = (" << euid <<","<< egid <<")" << endl; 
00313    cout << "XrdSysPriv: saved      = (" << suid <<","<< sgid <<")" << endl; 
00314    cout << "XrdSysPriv: "  << endl; 
00315    XrdSysPriv::fgMutex.UnLock();
00316 #endif
00317 }
00318 
00319 //
00320 // Guard class
00321 //______________________________________________________________________________
00322 XrdSysPrivGuard::XrdSysPrivGuard(uid_t uid, gid_t gid)
00323 {
00324    // Constructor. Create a guard object for temporarly change to privileges
00325    // of {'uid', 'gid'}
00326 
00327    dum = 1;
00328    valid = 0;
00329 
00330    Init(uid, gid);
00331 }
00332 
00333 //______________________________________________________________________________
00334 XrdSysPrivGuard::XrdSysPrivGuard(const char *usr)
00335 {
00336    // Constructor. Create a guard object for temporarly change to privileges
00337    // of 'usr'
00338 
00339    dum = 1;
00340    valid = 0;
00341 
00342 #if !defined(WINDOWS)
00343    if (usr && strlen(usr) > 0) {
00344       struct passwd *pw = getpwnam(usr);
00345       if (pw)
00346          Init(pw->pw_uid, pw->pw_gid);
00347    }
00348 #else
00349    if (usr) { }
00350 #endif
00351 }
00352 
00353 //______________________________________________________________________________
00354 XrdSysPrivGuard::~XrdSysPrivGuard()
00355 {
00356    // Destructor. Restore state and unlock the global mutex.
00357 
00358    if (!dum) {
00359       XrdSysPriv::Restore();
00360       XrdSysPriv::fgMutex.UnLock();
00361    }
00362 }
00363 
00364 //______________________________________________________________________________
00365 void XrdSysPrivGuard::Init(uid_t uid, gid_t gid)
00366 {
00367    // Init a change of privileges guard. Act only if superuser.
00368    // The result of initialization can be tested with the Valid() method.
00369 
00370    dum = 1;
00371    valid = 1;
00372 
00373    // Debug hook
00374    if (XrdSysPriv::fDebug)
00375       XrdSysPriv::DumpUGID("before Init()");
00376 
00377 #if !defined(WINDOWS)
00378    XrdSysPriv::fgMutex.Lock();
00379    uid_t ruid = 0, euid = 0, suid = 0;
00380    gid_t rgid = 0, egid = 0, sgid = 0;
00381    if (getresuid(&ruid, &euid, &suid) == 0 &&
00382        getresgid(&rgid, &egid, &sgid) == 0) {
00383       if ((euid != uid) || (egid != gid)) {
00384          if (!ruid) {
00385             // Change temporarly identity
00386             if (XrdSysPriv::ChangeTo(uid, gid) != 0)
00387                valid = 0;
00388             dum = 0;
00389          } else {
00390             // Change requested but not enough privileges
00391             valid = 0;
00392          }
00393       }
00394    } else {
00395       // Something bad happened: memory corruption?
00396       valid = 0;
00397    }
00398    // Unlock if no action
00399    if (dum)
00400       XrdSysPriv::fgMutex.UnLock();
00401 #endif
00402    // Debug hook
00403    if (XrdSysPriv::fDebug)
00404       XrdSysPriv::DumpUGID("after Init()");
00405 }

Generated on Tue Jul 5 14:47:03 2011 for ROOT_528-00b_version by  doxygen 1.5.1