/******************************************************************************/ /* */ /* X r d S e c g s i P r o x y . c c */ /* */ /* (c) 2005, G. Ganis / CERN */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /* */ /******************************************************************************/ /* ************************************************************************** */ /* */ /* Manage GSI proxies */ /* */ /* ************************************************************************** */ #include #include #include #include #include #include #include #include #include #include "XrdOuc/XrdOucString.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysPwd.hh" #include "XrdSut/XrdSutAux.hh" #include "XrdCrypto/XrdCryptoAux.hh" #include "XrdCrypto/XrdCryptoFactory.hh" #include "XrdCrypto/XrdCryptoX509.hh" #include "XrdCrypto/XrdCryptoX509Req.hh" #include "XrdCrypto/XrdCryptoX509Chain.hh" #include "XrdCrypto/XrdCryptoX509Crl.hh" #include "XrdCrypto/XrdCryptogsiX509Chain.hh" #include "XrdSecgsi/XrdSecgsiTrace.hh" #define PRT(x) {cerr <What |= (TRACE_Authen | TRACE_Debug); } // // Set debug flags in other modules if (Debug) { XrdSutSetTrace(sutTRACE_Debug); XrdCryptoSetTrace(cryptoTRACE_Debug); } // // Load the crypto factory if (!(gCryptoFactory = XrdCryptoFactory::GetCryptoFactory(CryptoMod.c_str()))) { PRT(": cannot instantiate factory "<SetTrace(cryptoTRACE_Debug); // Hooks for specific functionality if (!(ParseFile = gCryptoFactory->X509ParseFile())) { PRT("cannot attach to X509ParseFile function!"); exit(1); } if (!(CreateProxy = gCryptoFactory->X509CreateProxy())) { PRT("cannot attach to X509CreateProxy function!"); exit(1); } if (!(ProxyCertInfo = gCryptoFactory->ProxyCertInfo())) { PRT("cannot attach to ProxyCertInfo function!"); exit(1); } if (!(GetVOMSAttr = gCryptoFactory->X509GetVOMSAttr())) { PRT("cannot attach to X509GetVOMSAttr function!"); exit(1); } // // Depending on the mode switch (Mode) { case kM_help: // // We should not get here ... print the menu and go Menu(); break; case kM_init: // // Init proxies secValid = XrdSutParseTime(Valid.c_str(), 1); pxopt.bits = Bits; pxopt.valid = secValid; pxopt.depthlen = PathLength; cPXp = new XrdCryptogsiX509Chain(); // // Display info about existing proxies prc = (*CreateProxy)(EEcert.c_str(), EEkey.c_str(), &pxopt, cPXp, &kPXp, PXcert.c_str()); if (prc == 0) { // The proxy is the first certificate xPXp = cPXp->Begin(); if (xPXp) { Display(xPXp); } else { PRT( ": proxy certificate not found"); } } else { PRT( ": problems creating proxy"); } break; case kM_destroy: // // Destroy existing proxies if (unlink(PXcert.c_str()) == -1) { perror("xrdgsiproxy"); } break; case kM_info: // // Display info about existing proxies // Parse the proxy file cPXp = new XrdCryptogsiX509Chain(); nci = (*ParseFile)(PXcert.c_str(), cPXp); if (nci < 2) { if (Exists) { exitrc = 1; } else { PRT("proxy files must have at least two certificates" " (found only: "<Begin(); if (xPXp) { if (!Exists) { Display(xPXp); if (strstr(xPXp->Subject(), "CN=limited proxy")) { xPXPp = cPXp->SearchBySubject(xPXp->Issuer()); if (xPXPp) { Display(xPXPp); } else { PRT("WARNING: found 'limited proxy' but not the associated proxy!"); } } } else { // Check time validity secValid = XrdSutParseTime(Valid.c_str(), 1); int tl = xPXp->NotAfter() -(int)time(0); if (Debug) PRT("secValid: " << secValid<< ", tl: "< tl + ClockSkew) { exitrc = 1; break; } // Check bit strenght if (Debug) PRT("BitStrength: " << xPXp->BitStrength()<< ", Bits: "<BitStrength() < Bits) { exitrc = 1; break; } } } else { if (Exists) { exitrc = 1; } else { PRT( ": proxy certificate not found"); } } break; default: // // Print menu Menu(); } exit(exitrc); } int ParseArguments(int argc, char **argv) { // Parse application arguments filling relevant global variables // Number of arguments if (argc < 0 || !argv[0]) { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Insufficient number or arguments! +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); // Print main menu Menu(); return 1; } --argc; ++argv; // // Loop over arguments while ((argc >= 0) && (*argv)) { XrdOucString opt = ""; int ival = -1; if(*(argv)[0] == '-') { opt = *argv; opt.erase(0,1); if (CheckOption(opt,"h",ival) || CheckOption(opt,"help",ival) || CheckOption(opt,"menu",ival)) { Mode = kM_help; } else if (CheckOption(opt,"debug",ival)) { Debug = ival; } else if (CheckOption(opt,"e",ival)) { Exists = 1; } else if (CheckOption(opt,"exists",ival)) { Exists = 1; } else if (CheckOption(opt,"f",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { PXcert = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-f' requires a proxy file name: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"file",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { PXcert = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-file' requires a proxy file name: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"out",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { PXcert = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-out' requires a proxy file name: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"cert",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { EEcert = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-cert' requires a cert file name: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"key",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { EEkey = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-key' requires a key file name: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"certdir",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { CAdir = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-certdir' requires a dir path: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"valid",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { Valid = *argv; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-valid' requires a time string: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"path-length",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { PathLength = strtol(*argv,0,10); if (PathLength < -1 || errno == ERANGE) { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-path-length' requires a number >= -1: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-path-length' requires a number >= -1: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"bits",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { Bits = strtol(*argv, 0, 10); Bits = (Bits > 512) ? Bits : 512; if (errno == ERANGE) { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-bits' requires a number: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-bits' requires a number: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"clockskew",ival)) { --argc; ++argv; if (argc >= 0 && (*argv && *(argv)[0] != '-')) { ClockSkew = strtol(*argv, 0, 10); if (ClockSkew < -1 || errno == ERANGE) { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-clockskew' requires a number >= -1: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Option '-clockskew' requires a number >= -1: ignoring +"); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); argc++; argv--; } } else if (CheckOption(opt,"extensions",ival)) { DumpExtensions = 1; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Ignoring unrecognized option: "<<*argv); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); } } else { // // Mode keyword opt = *argv; if (CheckOption(opt,"init",ival)) { Mode = kM_init; } else if (CheckOption(opt,"info",ival)) { Mode = kM_info; } else if (CheckOption(opt,"destroy",ival)) { Mode = kM_destroy; } else if (CheckOption(opt,"help",ival)) { Mode = kM_help; } else { PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Ignoring unrecognized keyword mode: "<pw_uid); } // // Expand Path XrdSutExpand(PXcert); // Get info struct stat st; if (stat(PXcert.c_str(),&st) != 0) { if (errno != ENOENT) { // Path exists but we cannot access it - exit PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); PRT("+ Cannot access requested proxy file: "<] [options] "); PRT(" "); PRT(" "); PRT(" -h display this menu"); PRT(" "); PRT(" mode (info, init, destroy) [info]"); PRT(" "); PRT(" info: display content of existing proxy file"); PRT(" "); PRT(" init: create proxy certificate and related proxy file"); PRT(" "); PRT(" destroy: delete existing proxy file"); PRT(" "); PRT(" options:"); PRT(" "); PRT(" -debug Print more information while running this" " query (use if something goes wrong) "); PRT(" "); PRT(" -f,-file,-out Non-standard location of proxy file"); PRT(" "); PRT(" init mode only:"); PRT(" "); PRT(" -certdir Non-standard location of directory" " with information about known CAs"); PRT(" -cert Non-standard location of certificate" " for which proxies are wanted"); PRT(" -key Non-standard location of the private" " key to be used to sign the proxy"); PRT(" -bits strength in bits of the key [512]"); PRT(" -valid Time validity of the proxy certificate [12:00]"); PRT(" -path-length max number of descendent levels below" " this proxy [0] "); PRT(" -e,-exists [options] returns 0 if valid proxy exists, 1 otherwise;"); PRT(" valid options: '-valid ', -bits "); PRT(" -clockskew max clock-skewness allowed when checking time validity [30 secs]"); PRT(" -extensions low-level dump of certificate extensions"); PRT(" "); } bool CheckOption(XrdOucString opt, const char *ref, int &ival) { // Check opt against ref // Return 1 if ok, 0 if not // Fills ival = 1 if match is exact // ival = 0 if match is exact with no // ival = -1 in the other cases bool rc = 0; int lref = (ref) ? strlen(ref) : 0; if (!lref) return rc; XrdOucString noref = ref; noref.insert("no",0); ival = -1; if (opt == ref) { ival = 1; rc = 1; } else if (opt == noref) { ival = 0; rc = 1; } return rc; } void Display(XrdCryptoX509 *xp) { // display content of proxy certificate PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); if (!xp) { PRT(" Empty certificate! "); return; } // File PRT("file : "<type != XrdCryptoX509::kProxy) { PRT("type : "<Type()); } else { PRT("type : "<Type()<<" ("<ProxyType()<<")"); } // Issuer PRT("issuer : "<Issuer()); // Subject PRT("subject : "<Subject()); // Path length field int pathlen = 0; bool b; if(xp->GetExtension(gsiProxyCertInfo_OID)) (*ProxyCertInfo)(xp->GetExtension(gsiProxyCertInfo_OID), pathlen, &b); else (*ProxyCertInfo)(xp->GetExtension(gsiProxyCertInfo_OLD_OID), pathlen, &b); PRT("path length : "<BitStrength()); // Time left int now = int(time(0)) - XrdCryptoTZCorr(); int tl = xp->NotAfter() - now; int hh = (tl >= 3600) ? (tl/3600) : 0; tl -= (hh*3600); int mm = (tl >= 60) ? (tl/60) : 0; tl -= (mm*60); int ss = (tl >= 0) ? tl : 0; PRT("time left : "< 0) PRT("VOMS attributes: "<SetTrace(cryptoTRACE_Debug); xp->DumpExtensions(0); PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); } }