/******************************************************************************/
/* */
/* 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("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
}
}
]