XrdSecProtocolpwd.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                 X r d S e c P r o t o c o l p w d . c c                    */
00004 /*                                                                            */
00005 /* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC03-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 #include <unistd.h>
00012 #include <ctype.h>
00013 #include <errno.h>
00014 #include <stdlib.h>
00015 #include <strings.h>
00016 #include <stdio.h>
00017 #include <sys/param.h>
00018 #include <pwd.h>
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <fcntl.h>
00022 #include <sys/times.h>
00023 
00024 // AFS support
00025 #ifdef R__AFS
00026 extern "C" {
00027 #include <afs/stds.h>
00028 #include <afs/kautils.h>
00029 afs_int32 ka_Authenticate(char *name, char *instance, char *cell,
00030                           struct ubik_client *conn, int service,
00031                           struct ktc_encryptionKey *key, Date start,
00032                           Date end, struct ktc_token *token,
00033                           afs_int32 * pwexpires);
00034 afs_int32 ka_ReadPassword(char *prompt, int verify, char *cell,
00035                           struct ktc_encryptionKey *key);
00036 afs_int32 ka_AuthServerConn(char *cell, int service,
00037                             struct ktc_token *token,
00038                             struct ubik_client **conn);
00039 char     *ka_LocalCell();
00040 void      ka_StringToKey(char *str, char *cell,
00041                          struct ktc_encryptionKey *key);
00042 }
00043 #endif
00044 
00045 #include "XrdSys/XrdSysHeaders.hh"
00046 #include <XrdSys/XrdSysLogger.hh>
00047 #include <XrdSys/XrdSysError.hh>
00048 #include <XrdOuc/XrdOucStream.hh>
00049 
00050 #include <XrdSys/XrdSysPriv.hh>
00051 
00052 #include <XrdSut/XrdSutCache.hh>
00053 
00054 #include <XrdSecpwd/XrdSecProtocolpwd.hh>
00055 #include <XrdSecpwd/XrdSecpwdPlatform.hh>
00056 
00057 /******************************************************************************/
00058 /*                           S t a t i c   D a t a                            */
00059 /******************************************************************************/
00060   
00061 static String Prefix   = "xrd";
00062 static String ProtoID  = XrdSecPROTOIDENT;
00063 static const kXR_int32 Version = XrdSecpwdVERSION;
00064 static String AdminRef = ProtoID + "admin";
00065 static String SrvPukRef= ProtoID + "srvpuk";
00066 static String UserRef  = ProtoID + "user";
00067 static String NetRcRef = ProtoID + "netrc";
00068 
00069 static const char *pwdClientSteps[] = {
00070    "kXPC_none",
00071    "kXPC_normal",
00072    "kXPC_verifysrv",
00073    "kXPC_signedrtag",
00074    "kXPC_creds",
00075    "kXPC_autoreg",
00076    "kXPC_failureack",
00077    "kXPC_reserved"
00078 };
00079 
00080 static const char *pwdServerSteps[] = {
00081    "kXPS_none",
00082    "kXPS_init",
00083    "kXPS_credsreq",
00084    "kXPS_rtag",
00085    "kXPS_signedrtag",
00086    "kXPS_newpuk",
00087    "kXPS_puk",
00088    "kXPS_failure",
00089    "kXPS_reserved"
00090 };
00091 
00092 static const char *gPWErrStr[] = {
00093    "parsing buffer",                     // 10000
00094    "decoding buffer",                    // 10001
00095    "loading crypto factory",             // 10002
00096    "protocol mismatch",                  // 10003
00097    "resolving user / host",              // 10004
00098    "user missing",                       // 10005
00099    "host missing",                       // 10006
00100    "unknown user",                       // 10007
00101    "creating bucket",                    // 10008
00102    "duplicating bucket",                 // 10009
00103    "creating buffer",                    // 10010
00104    "serializing buffer",                 // 10011
00105    "generating cipher",                  // 10012
00106    "exporting public key",               // 10013
00107    "encrypting random tag",              // 10014
00108    "random tag mismatch",                // 10015
00109    "random tag missing",                 // 10016
00110    "cipher missing",                     // 10017
00111    "getting credentials",                // 10018
00112    "credentials missing",                // 10019
00113    "wrong password for user",            // 10020
00114    "checking cache",                     // 10021
00115    "cache entry for link missing",       // 10022
00116    "session handshaking ID missing",     // 10023
00117    "session handshaking ID mismatch",    // 10024
00118    "unknown step option",                // 10025
00119    "marshaling integer",                 // 10026
00120    "unmarshaling integer",               // 10027
00121    "saving new credentials",             // 10028
00122    "salt missing",                       // 10029
00123    "buffer empty",                       // 10030
00124    "obtaining reference cipher",         // 10031
00125    "obtaining cipher public info",       // 10032
00126    "adding bucket to list",              // 10033
00127    "finalizing cipher from public info", // 10034
00128    "error during initialization",        // 10035
00129    "wrong credentials",                  // 10035
00130    "error"                               // 10036    
00131 };
00132 
00133 // Masks for options
00134 static const short kOptsServer  = 0x0001;
00135 static const short kOptsUserPwd = 0x0002;
00136 static const short kOptsAutoReg = 0x0004;
00137 static const short kOptsAregAll = 0x0008;
00138 static const short kOptsVeriSrv = 0x0020;
00139 static const short kOptsVeriClt = 0x0040;
00140 static const short kOptsClntTty = 0x0080;
00141 static const short kOptsExpCred = 0x0100;
00142 static const short kOptsCrypPwd = 0x0200;
00143 static const short kOptsChngPwd = 0x0400;
00144 static const short kOptsAFSPwd  = 0x0800;
00145 // One day in secs
00146 static const int kOneDay = 86400; 
00147 
00148 /******************************************************************************/
00149 /*                     S t a t i c   C l a s s   D a t a                      */
00150 /******************************************************************************/
00151 XrdSysMutex XrdSecProtocolpwd::pwdContext;
00152 String XrdSecProtocolpwd::FileAdmin= "";
00153 String XrdSecProtocolpwd::FileExpCreds= "";
00154 String XrdSecProtocolpwd::FileUser = "";
00155 String XrdSecProtocolpwd::FileCrypt= "/.xrdpass";
00156 String XrdSecProtocolpwd::FileSrvPuk= "";
00157 String XrdSecProtocolpwd::SrvID    = "";
00158 String XrdSecProtocolpwd::SrvEmail = "";
00159 String XrdSecProtocolpwd::DefCrypto= "ssl";
00160 String XrdSecProtocolpwd::DefError = "insufficient credentials - contact ";
00161 XrdSutPFile XrdSecProtocolpwd::PFAdmin(0);   // Admin file (server)
00162 XrdSutPFile XrdSecProtocolpwd::PFAlog(0);   // Autologin file (client)
00163 XrdSutPFile XrdSecProtocolpwd::PFSrvPuk(0);  // File with server public keys (client)
00164 //
00165 // Crypto related info
00166 int  XrdSecProtocolpwd::ncrypt    = 0;                 // Number of factories
00167 int  XrdSecProtocolpwd::cryptID[XrdCryptoMax] = {0};   // their IDs 
00168 String XrdSecProtocolpwd::cryptName[XrdCryptoMax] = {0}; // their names 
00169 XrdCryptoCipher *XrdSecProtocolpwd::refcip[XrdCryptoMax] = {0};    // ref for session ciphers 
00170 //
00171 // Caches for info files
00172 XrdSutCache XrdSecProtocolpwd::cacheAdmin;  // Admin file
00173 XrdSutCache XrdSecProtocolpwd::cacheSrvPuk; // SrvPuk file
00174 XrdSutCache XrdSecProtocolpwd::cacheUser;   // User files
00175 XrdSutCache XrdSecProtocolpwd::cacheAlog;   // Autologin file
00176 //
00177 // Running options / settings
00178 int  XrdSecProtocolpwd::Debug       = 0; // [CS] Debug level
00179 bool XrdSecProtocolpwd::Server      = 1; // [CS] If server mode 
00180 int  XrdSecProtocolpwd::UserPwd     = 0; // [S] Check passwd file in user's <xrdsecdir> 
00181 bool XrdSecProtocolpwd::SysPwd      = 0; // [S] Check passwd file in user's <xrdsecdir> 
00182 int  XrdSecProtocolpwd::VeriClnt    = 2; // [S] Client authenticity verification level:
00183                                          //     0  none, 1 timestamp, 2 random tag      
00184 int  XrdSecProtocolpwd::VeriSrv     = 1; // [C] Server authenticity verification level:
00185                                          //     0  none, 1 random tag      
00186 int  XrdSecProtocolpwd::AutoReg     = kpAR_none; // [S] Autoreg mode 
00187 int  XrdSecProtocolpwd::LifeCreds   = 0; // [S] if > 0, time interval of validity for creds
00188 int  XrdSecProtocolpwd::MaxPrompts  = 3; // [C] Repeating prompt
00189 int  XrdSecProtocolpwd::MaxFailures = 10;// [S] Max passwd failures before blocking
00190 int  XrdSecProtocolpwd::AutoLogin   = 0; // [C] do-not-check/check/update autologin info
00191 int  XrdSecProtocolpwd::TimeSkew    = 300; // [CS] Allowed skew in secs for time stamps 
00192 bool XrdSecProtocolpwd::KeepCreds   = 0; // [S] Keep / Do-Not-Keep client creds 
00193 //
00194 // Debug an tracing
00195 XrdSysError    XrdSecProtocolpwd::eDest(0, "secpwd_");
00196 XrdSysLogger   XrdSecProtocolpwd::Logger;
00197 XrdOucTrace   *XrdSecProtocolpwd::SecTrace = 0;
00198 
00199 /******************************************************************************/
00200 /*                    S t a t i c   F u n c t i o n s                         */
00201 /******************************************************************************/
00202 //_____________________________________________________________________________
00203 static const char *ClientStepStr(int kclt)
00204 {
00205    // Return string with client step  
00206    static const char *ukn = "Unknown";
00207 
00208    kclt = (kclt < 0) ? 0 : kclt;
00209    kclt = (kclt > kXPC_reserved) ? 0 : kclt;
00210    kclt = (kclt >= kXPC_normal) ? (kclt - kXPC_normal + 1) : kclt;
00211 
00212    if (kclt < 0 || kclt > (kXPC_reserved - kXPC_normal + 1))
00213       return ukn;  
00214    else
00215       return pwdClientSteps[kclt];
00216 }
00217 
00218 //_____________________________________________________________________________
00219 static const char *ServerStepStr(int ksrv)
00220 {
00221    // Return string with server step  
00222    static const char *ukn = "Unknown";
00223 
00224    ksrv = (ksrv < 0) ? 0 : ksrv;
00225    ksrv = (ksrv > kXPS_reserved) ? 0 : ksrv;
00226    ksrv = (ksrv >= kXPS_init) ? (ksrv - kXPS_init + 1) : ksrv;
00227 
00228    if (ksrv < 0 || ksrv > (kXPS_reserved - kXPS_init + 1))
00229       return ukn;  
00230    else
00231       return pwdServerSteps[ksrv];
00232 }
00233 
00234 /******************************************************************************/
00235 /*       P r o t o c o l   I n i t i a l i z a t i o n   M e t h o d s        */
00236 /******************************************************************************/
00237 
00238 
00239 //_____________________________________________________________________________
00240 XrdSecProtocolpwd::XrdSecProtocolpwd(int opts, const char *hname,
00241                                      const struct sockaddr *ipadd,
00242                                      const char *parms) : XrdSecProtocol("pwd")
00243 {
00244    // Default constructor
00245    EPNAME("XrdSecProtocolpwd");
00246 
00247    if (QTRACE(Authen)) { PRINT("constructing: "<<this); }
00248 
00249    // Create instance of the handshake vars
00250    if ((hs = new pwdHSVars())) {
00251       // Update time stamp
00252       hs->TimeStamp = time(0);
00253       // Local handshake variables
00254       hs->CryptoMod = "";       // crypto module in use
00255       hs->User = "";            // remote username
00256       hs->Tag.resize(256);      // tag for credentials
00257       hs->RemVers = -1;         // Version run by remote counterpart
00258       hs->CF = 0;               // crypto factory
00259       hs->Hcip = 0;             // handshake cipher
00260       hs->Rcip = 0;             // reference cipher
00261       hs->ID = "";              // Handshake ID (dummy for clients)
00262       hs->Cref = 0;             // Cache reference
00263       hs->Pent = 0;             // Pointer to relevant file entry
00264       hs->RtagOK = 0;           // Rndm tag checked / not checked
00265       hs->Tty = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
00266       hs->Step = 0;             // Current step
00267       hs->LastStep = 0;         // Step required at previous iteration
00268    } else {
00269       DEBUG("could not create handshake vars object");
00270    }
00271 
00272    // Used by servers to store forwarded credentials
00273    clientCreds = 0;
00274 
00275    // Save host name
00276    if (hname) {
00277       Entity.host = strdup(hname);
00278    } else {
00279       DEBUG("warning: host name undefined");
00280    }
00281    // Save host addr
00282    memcpy(&hostaddr, ipadd, sizeof(hostaddr));
00283    // Init client name
00284    CName[0] = '?'; CName[1] = '\0';
00285 
00286    //
00287    // Notify, if required
00288    DEBUG("constructing: host: "<<hname);
00289    DEBUG("p: "<<XrdSecPROTOIDENT<<", plen: "<<XrdSecPROTOIDLEN);
00290    //
00291    // basic settings
00292    options  = opts;
00293 
00294    //
00295    // Mode specific initializations
00296    if (Server) {
00297       srvMode = 1;
00298       DEBUG("mode: server");
00299    } else {
00300       srvMode = 0;
00301       DEBUG("mode: client");
00302       if (AutoLogin > 0) {
00303          DEBUG("using autologin file: "<<PFAlog.Name());
00304          if (AutoLogin > 1) {
00305             DEBUG("running in update-autologin mode");
00306          }
00307       }
00308       if (VeriSrv > 0) {
00309          DEBUG("server verification ON");
00310       } else {
00311          DEBUG("server verification OFF");
00312       }
00313       // Decode received buffer
00314       if (parms) {
00315          XrdOucString p("&P=pwd,");
00316          p += parms;
00317          hs->Parms = new XrdSutBuffer(p.c_str(), p.length());
00318       }
00319    }
00320 
00321    // We are done
00322    String vers = Version;
00323    vers.insert('.',vers.length()-2);
00324    vers.insert('.',vers.length()-5);
00325    DEBUG("object created: v"<<vers.c_str());
00326 }
00327 
00328 //_____________________________________________________________________________
00329 char *XrdSecProtocolpwd::Init(pwdOptions opt, XrdOucErrInfo *erp)
00330 {
00331    // Static method to the configure the static part of the protocol
00332    // Called once by XrdSecProtocolpwdInit
00333    EPNAME("Init");
00334    char *Parms = 0;
00335    //
00336    // Debug an tracing
00337    Debug = (opt.debug > -1) ? opt.debug : Debug;
00338    // Initiate error logging and tracing
00339    eDest.logger(&Logger);
00340    SecTrace    = new XrdOucTrace(&eDest);
00341    // Set debug mask ... also for auxilliary libs
00342    int trace = 0;
00343    if (Debug >= 3) {
00344       trace = cryptoTRACE_Dump;
00345       SecTrace->What |= TRACE_Authen;
00346       SecTrace->What |= TRACE_Debug;
00347    } else if (Debug >= 1) {
00348       trace = cryptoTRACE_Debug;
00349       SecTrace->What = TRACE_Debug;
00350    }
00351    // ... also for auxilliary libs
00352    XrdSutSetTrace(trace);
00353    XrdCryptoSetTrace(trace);
00354 
00355    // Get user info
00356    struct passwd *pw = getpwuid(getuid());
00357    if (!pw) {
00358       PRINT("no user info available - invalid ");
00359       ErrF(erp, kPWErrInit, "could not get user info from getpwuid");
00360       return Parms;
00361    }
00362 
00363    //
00364    // Operation mode
00365    Server = (opt.mode == 's');
00366 
00367    //
00368    // Directory with admin pwd files
00369    bool argdir = 0;
00370    String infodir(512);
00371    if (opt.dir) {
00372       infodir = opt.dir;
00373       // Expand
00374       if (XrdSutExpand(infodir) != 0) {
00375          PRINT("cannot expand "<<opt.dir);
00376          infodir = "";
00377       }
00378       argdir = 1;
00379    } else {
00380       // use default dir $(HOME)/.<prefix>
00381       infodir = XrdSutHome();
00382       infodir += ("/." + Prefix);
00383    }
00384    if (!infodir.endswith("/")) infodir += "/";
00385    //
00386    // If defined, check existence of the infodir and admin file
00387    if (infodir.length()) {
00388       // Acquire the privileges, if needed
00389       XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
00390       if (priv.Valid()) {
00391          struct stat st;
00392          if (stat(infodir.c_str(),&st) == -1) {
00393             if (errno == ENOENT) {
00394                if (argdir) {
00395                   DEBUG("infodir non existing: "<<infodir.c_str());
00396                } else {
00397                   DEBUG("creating infodir: "<<infodir.c_str());
00398                   if (XrdSutMkdir(infodir.c_str(),0777) != 0) {
00399                      DEBUG("cannot create infodir (errno: "<<errno<<")");
00400                      infodir = "";
00401                      argdir = 0;
00402                   }
00403                }
00404             } else {
00405                DEBUG("cannot stat infodir "<<infodir<<" (errno: "<<errno<<")");
00406                infodir = "";
00407                argdir = 0;
00408             }
00409          }
00410       }
00411    }
00412    DEBUG("using infodir: "<<infodir.c_str());
00413 
00414    //
00415    // Server specific options
00416    if (Server) {
00417       //
00418       // Auto registration
00419       AutoReg = (opt.areg > -1) ? opt.areg : AutoReg;
00420       //
00421       // Client verification level
00422       VeriClnt = (opt.vericlnt > -1) ? opt.vericlnt : VeriClnt;
00423       //
00424       // Whether to check pwd files in users' $HOME
00425       UserPwd = (opt.upwd > -1) ? opt.upwd : UserPwd;
00426       //
00427       // Whether to check system pwd files (if allowed)
00428       SysPwd = (opt.syspwd > -1) ? opt.syspwd : SysPwd;
00429       if (SysPwd) {
00430          // Make sure this setting makes sense
00431          if (pw) {
00432 #ifndef R__AFS
00433 #ifdef R__SHADOWPW
00434             // Acquire the privileges, if needed
00435             XrdSysPrivGuard priv((uid_t) 0, (gid_t) 0);
00436             if (priv.Valid()) {
00437                // System V Rel 4 style shadow passwords
00438                struct spwd *spw = getspnam(pw->pw_name);
00439                if (!spw) {
00440                   SysPwd = 0;
00441                   DEBUG("no privileges to access shadow passwd file");
00442                }
00443             } else {
00444                DEBUG("problems acquiring credentials"
00445                      " to access the system password file");
00446             }
00447 #else
00448             // Normal passwd file
00449             if (!pw->pw_passwd &&
00450                 (pw->pw_passwd && strlen(pw->pw_passwd) <= 1)) {
00451                SysPwd = 0;
00452                DEBUG("no privileges to access system passwd file");
00453             }
00454 #endif
00455 #else
00456             PRINT("configured with AFS support");
00457 #endif
00458          } else
00459             SysPwd = 0;
00460       }
00461       //
00462       // Credential  lifetime
00463       LifeCreds = (opt.lifecreds > -1) ? opt.lifecreds : LifeCreds;
00464       //
00465       // Max number of failures
00466       MaxFailures = (opt.maxfailures > -1) ? opt.maxfailures : MaxFailures;
00467 
00468       //
00469       // If defined, check existence of the infodir and admin file
00470       if (infodir.length()) {
00471          // Acquire the privileges, if needed
00472          XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
00473          if (priv.Valid()) {
00474             struct stat st;
00475             //
00476             // Define admin file and check its existence
00477             FileAdmin = infodir + AdminRef;
00478             if (stat(FileAdmin.c_str(),&st) == -1) {
00479                if (errno == ENOENT) {
00480                   PRINT("FileAdmin non existing: "<<FileAdmin.c_str());
00481                } else {
00482                   PRINT("cannot stat FileAdmin (errno: "<<errno<<")");
00483                }
00484                FileAdmin = "";
00485                if (UserPwd == 0 && !SysPwd) {
00486                   PRINT("no passwd info available - invalid ");
00487                   ErrF(erp,kPWErrInit,"could not find a valid password file");
00488                   return Parms;
00489                }
00490             }
00491             if (FileAdmin.length() > 0) {
00492                //
00493                // Load server ID
00494                PFAdmin.Init(FileAdmin.c_str(),0);
00495                if (PFAdmin.IsValid()) {
00496                   //
00497                   // Init cache for admin file
00498                   if (cacheAdmin.Load(FileAdmin.c_str()) != 0) {
00499                      PRINT("problems init cache for file admin ");
00500                      ErrF(erp,kPWErrError,"initializing cache for file admin");
00501                      return Parms;
00502                   }
00503                   if (QTRACE(Authen)) { cacheAdmin.Dump(); }
00504                   XrdSutPFEntry *ent = cacheAdmin.Get("+++SrvID");
00505                   if (ent)
00506                      SrvID.insert(ent->buf1.buf, 0, ent->buf1.len);
00507                   ent = cacheAdmin.Get("+++SrvEmail");
00508                   if (ent)
00509                      SrvEmail.insert(ent->buf1.buf, 0, ent->buf1.len);
00510                   // Default error message
00511                   DefError += SrvEmail;
00512                }
00513                DEBUG("server ID: "<<SrvID);
00514                DEBUG("contact e-mail: "<<SrvEmail);
00515             }
00516          }
00517       } else if (UserPwd == 0 && !SysPwd) {
00518          PRINT("no passwd info available - invalid ");
00519          ErrF(erp,kPWErrError,"could not find a valid password file");
00520          return Parms;
00521       }
00522       //
00523       // Init cache for user pwd information
00524       if (UserPwd > 0 || SysPwd) {
00525          if (cacheUser.Init(100) != 0) {
00526             PRINT("problems init cache for user pwd info"
00527                   " - passwd files in user accounts will not be used");
00528             UserPwd = 0;
00529          }
00530       }
00531 
00532       //
00533       // List of crypto modules
00534       String cryptlist = opt.clist ? (const char *)(opt.clist) : DefCrypto;
00535 
00536       // 
00537       // Load crypto modules
00538       XrdSutPFEntry ent;
00539       XrdCryptoFactory *cf = 0;
00540       String clist = cryptlist;
00541       if (clist.length()) {
00542          String ncpt = "";
00543          int from = 0;
00544          while ((from = clist.tokenize(ncpt, from, '|')) != -1) {
00545             if (ncpt.length() > 0) {
00546                // Try loading 
00547                if ((cf = XrdCryptoFactory::GetCryptoFactory(ncpt.c_str()))) {
00548                   // Add it to the list
00549                   cryptID[ncrypt] = cf->ID();
00550                   cryptName[ncrypt].insert(cf->Name(),0,strlen(cf->Name())+1);
00551                   cf->SetTrace(trace);
00552                   // Ref cipher
00553                   String ptag("+++SrvPuk_");
00554                   ptag += cf->ID();
00555                   if (FileAdmin.length() > 0) {
00556                      // Acquire the privileges, if needed
00557                      XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
00558                      if (priv.Valid()) {
00559                         if (PFAdmin.ReadEntry(ptag.c_str(),ent) <= 0) {
00560                            PRINT("ref cipher for module "<<ncpt<<" missing: disable");
00561                            cryptlist.erase(ncpt);
00562                         } else {
00563                            XrdSutBucket bck;
00564                            bck.SetBuf(ent.buf1.buf,ent.buf1.len);
00565                            if (!(refcip[ncrypt] = cf->Cipher(&bck))) {
00566                               PRINT("ref cipher for module "<<ncpt<<
00567                                     " cannot be instantiated : disable");
00568                               cryptlist.erase(ncpt);
00569                            } else {
00570                               ncrypt++;
00571                               if (ncrypt >= XrdCryptoMax) {
00572                                  PRINT("max number of crypto modules ("
00573                                         << XrdCryptoMax <<") reached ");
00574                                  break;
00575                               }
00576                            }
00577                         }
00578                      }
00579                   }
00580                } else {
00581                   PRINT("cannot instantiate crypto factory "<<ncpt);
00582                }
00583             }
00584          }
00585       }
00586 
00587       //
00588       // We need at least one valid crypto module
00589       if (ncrypt <= 0) {
00590          PRINT("could not find any valid crypto module");
00591          ErrF(erp,kPWErrInit,"could not find any valid crypto module");
00592          return Parms;
00593       }
00594 
00595       //
00596       // users' pwd information 
00597       if (UserPwd > 0) {
00598          FileUser = ("/" + UserRef);
00599          if (opt.udir) {
00600             FileUser.insert(opt.udir,0);
00601             if (FileUser[0] != '/') FileUser.insert('/',0);
00602          } else {
00603             // Use default $(HOME)/.<Prefix>
00604             FileUser.insert(Prefix,0);
00605             FileUser.insert("/.",0);
00606          }
00607          //
00608          // Crypt-hash file name, if requested
00609          if (opt.cpass) {
00610             UserPwd = 2;
00611             FileCrypt = opt.cpass;
00612             if (FileCrypt[0] != '/') FileCrypt.insert('/',0);
00613          }
00614       }
00615 
00616       //
00617       // Whether to save client creds
00618       KeepCreds = (opt.keepcreds > -1) ? opt.keepcreds : KeepCreds;
00619       if (KeepCreds)
00620          PRINT("Exporting client creds to internal buffer");
00621 
00622       //
00623       // Whether to export client creds to a file
00624       FileExpCreds = (opt.expcreds) ? opt.expcreds : FileExpCreds;
00625       if (FileExpCreds.length() > 0)
00626          PRINT("Exporting client creds to files "<<FileExpCreds);
00627 
00628       //
00629       // Priority option field
00630       String popt = "";
00631       if (SysPwd) {
00632 #ifndef R__AFS
00633          popt += "sys";
00634 #else
00635          popt += "afs";
00636          popt += ka_LocalCell();
00637 #endif
00638       }
00639 
00640       //
00641       // Parms in the form: &P=pwd,c:<cryptomod>,v:<version>,id:<srvid>
00642       Parms = new char[cryptlist.length()+3+12+SrvID.length()+5+popt.length()+3];
00643       if (Parms) {
00644          if (popt.length() > 0)
00645             sprintf(Parms,"v:%d,id:%s,c:%s,po:%s",
00646                           Version,SrvID.c_str(),cryptlist.c_str(),popt.c_str());
00647          else
00648             sprintf(Parms,"v:%d,id:%s,c:%s",
00649                           Version,SrvID.c_str(),cryptlist.c_str());
00650       } else {
00651          PRINT("no system resources for 'Parms'");
00652          ErrF(erp,kPWErrInit,"no system resources for 'Parms'");
00653       }
00654 
00655       // Some notification
00656       DEBUG("using FileAdmin: "<<FileAdmin);
00657       DEBUG("server ID: "<<SrvID);
00658       DEBUG("contact e-mail: "<<SrvEmail);
00659       DEBUG("auto-registration mode: "<<AutoReg);
00660       DEBUG("verify client mode: "<<VeriClnt);
00661       DEBUG("available crypto modules: "<<cryptlist);
00662       if (UserPwd > 0) {
00663          DEBUG("using private pwd files: $(HOME)"<<FileUser);
00664          if (UserPwd > 1) {
00665             DEBUG("using private crypt-hash files: $(HOME)"<<FileCrypt);
00666          }
00667       }
00668       if (SysPwd) {
00669 #ifndef R__AFS
00670          DEBUG("using system pwd information");
00671 #else
00672          DEBUG("using AFS information");
00673 #endif
00674       }
00675       if (KeepCreds) {
00676          DEBUG("client credentials will be kept");
00677       }
00678    }
00679 
00680    //
00681    // Client specific options
00682    if (!Server) {
00683       //
00684       // Server verification level
00685       VeriSrv = (opt.verisrv > -1) ? opt.verisrv : VeriSrv;
00686       //
00687       // Server puks file
00688       FileSrvPuk = "";
00689       if (opt.srvpuk) {
00690          FileSrvPuk = opt.srvpuk;
00691          if (XrdSutExpand(FileSrvPuk) != 0) {
00692             PRINT("cannot expand "<<opt.srvpuk);
00693             FileSrvPuk = "";
00694          }
00695       }
00696       //
00697       // If not defined, use default
00698       if (FileSrvPuk.length() <= 0 && infodir.length() > 0)
00699          FileSrvPuk = infodir + SrvPukRef;
00700 
00701       if (FileSrvPuk.length() > 0) {
00702          kXR_int32 openmode = 0; 
00703          struct stat st;
00704          //
00705          if (stat(FileSrvPuk.c_str(),&st) == -1) {
00706             if (errno == ENOENT) {
00707                PRINT("server public key file "<<FileSrvPuk<<" non existing: creating");
00708                openmode = kPFEcreate;
00709                // Make sure that the dir path exists
00710                XrdOucString dir = FileSrvPuk;
00711                dir.erase(dir.rfind('/')+1);
00712                DEBUG("asserting dir: "<<dir);
00713                if (XrdSutMkdir(dir.c_str(),0777) != 0) {
00714                   DEBUG("cannot create dir for srvpuk(errno: "<<errno<<")");
00715                   ErrF(erp,kPWErrInit,"cannot create dir for server public key file- exit");
00716                   return Parms;
00717                }
00718             } else {
00719                PRINT("cannot stat server public key file (errno: "<<errno<<")");
00720                FileSrvPuk = "";
00721                PRINT("server public key file invalid - exit");
00722                ErrF(erp,kPWErrInit,"server public key file invalid - exit");
00723                return Parms;
00724             }
00725          }
00726          //
00727          // Load server ID
00728          PFSrvPuk.Init(FileSrvPuk.c_str(),openmode);
00729          if (PFSrvPuk.IsValid()) {
00730             //
00731             // Init cache for server puk file
00732             if (cacheSrvPuk.Load(FileSrvPuk.c_str()) != 0) {
00733                PRINT("problems init cache for server public key file ");
00734                ErrF(erp,kPWErrError,"initializing cache for server public key file ");
00735                return Parms;
00736             }
00737             if (QTRACE(Authen)) { cacheSrvPuk.Dump(); }
00738          } else {
00739             PRINT("server public key file invalid ");
00740             ErrF(erp,kPWErrInit,"server public key file invalid");
00741             return Parms;
00742          }
00743       } else {
00744          PRINT("server public key file undefined");
00745          ErrF(erp,kPWErrInit,"server public key file undefined");
00746          return Parms;
00747       }
00748 
00749       //
00750       // Whether to search for autologin information
00751       AutoLogin = (opt.alog > -1) ? opt.alog : AutoLogin;
00752       DEBUG("AutoLogin level: "<<AutoLogin);
00753       //
00754       // Max number of re-prompts (for inconsistent inputs)
00755       MaxPrompts = (opt.maxprompts > -1) ? opt.maxprompts : MaxPrompts;
00756       //
00757       // Attach autologin file name, if requested
00758       if (AutoLogin > 0) {
00759          bool filefound = 0;
00760          String fnrc(256);
00761          if (opt.alogfile) {
00762             fnrc = opt.alogfile;
00763             if (XrdSutExpand(fnrc) != 0) {
00764                PRINT("cannot expand "<<opt.alogfile);
00765                fnrc = "";
00766             }
00767          }
00768          //
00769          // If file name not specified ...
00770          if (fnrc.length() <= 0)
00771             // use default
00772             fnrc = infodir + NetRcRef;
00773 
00774          if (fnrc.length() > 0) {
00775             kXR_int32 openmode = 0; 
00776             struct stat st;
00777             if (stat(fnrc.c_str(),&st) == -1) {
00778                if (errno == ENOENT) {
00779                   PRINT("Autologin file "<<fnrc<<" non existing: creating");
00780                   openmode = kPFEcreate;
00781                } else {
00782                   PRINT("cannot stat autologin file (errno: "<<errno<<")");
00783                   PRINT("switching off auto-login");
00784                   AutoLogin = 0;
00785                }
00786             }
00787 
00788             if (AutoLogin > 0) {
00789                // Attach to file
00790                PFAlog.Init(fnrc.c_str(),openmode);
00791                if (PFAlog.IsValid()) {
00792                   // Init cache for autologin file
00793                   if (cacheAlog.Load(fnrc.c_str()) == 0) {
00794                      if (QTRACE(Authen)) { cacheAlog.Dump(); }
00795                      filefound =1;
00796                   } else {
00797                      PRINT("problems init cache for autologin file");
00798                   }
00799                } else {
00800                   PRINT("problems attaching-to / creating autologin file");
00801                }
00802             }
00803          } 
00804          //
00805          // Notify if not found
00806          if (!filefound) {
00807             DEBUG("could not init properly autologin - switch off ");
00808             AutoLogin = 0;
00809          }
00810       }
00811       //
00812       // Notify if not found
00813       if (AutoLogin <= 0) {
00814          // Init anyhow cache to cache information during session
00815          if (cacheAlog.Init(100) != 0) {
00816             PRINT("problems init cache for user temporary autolog");
00817          }
00818       }
00819       // We are done
00820       Parms = (char *)"";
00821    }
00822 
00823    // We are done
00824    return Parms;
00825 }
00826 
00827 /******************************************************************************/
00828 /*                                D e l e t e                                 */
00829 /******************************************************************************/
00830 void XrdSecProtocolpwd::Delete()
00831 {
00832    // Deletes the protocol
00833    if (Entity.host) free(Entity.host);
00834    // Cleanup the handshake variables, if still there
00835    SafeDelete(hs);
00836    delete this;
00837 }
00838 
00839 /******************************************************************************/
00840 /*             C l i e n t   O r i e n t e d   F u n c t i o n s              */
00841 /******************************************************************************/
00842 /******************************************************************************/
00843 /*                        g e t C r e d e n t i a l s                         */
00844 /******************************************************************************/
00845 
00846 XrdSecCredentials *XrdSecProtocolpwd::getCredentials(XrdSecParameters *parm,
00847                                                      XrdOucErrInfo    *ei)
00848 {
00849    // Query client for the password; remote username and host
00850    // are specified in 'parm'. File '.rootnetrc' is checked. 
00851    EPNAME("getCredentials");
00852 
00853    // If we are a server the only reason to be here is to get the forwarded
00854    // or saved client credentials
00855    if (srvMode) {
00856       XrdSecCredentials *creds = 0;
00857       if (clientCreds) {
00858          // Duplicate the buffer (otherwise it will get deleted ...)
00859          int sz = clientCreds->size;
00860          char *nbuf = (char *) malloc(sz);
00861          if (nbuf) {
00862             memcpy(nbuf, clientCreds->buffer, sz);
00863             creds = new XrdSecCredentials(nbuf, sz);
00864          }
00865       }
00866       return creds;
00867    }
00868 
00869    // Handshake vars conatiner must be initialized at this point
00870    if (!hs)
00871       return ErrC(ei,0,0,0,kPWErrError,
00872                   "handshake var container missing","getCredentials");
00873    hs->ErrMsg = "";
00874 
00875    //
00876    // Nothing to do if buffer is empty and not filled during construction
00877    if ((!parm && !hs->Parms) || (parm && (!(parm->buffer) || parm->size <= 0)))
00878       return ErrC(ei,0,0,0,kPWErrNoBuffer,"missing parameters","getCredentials");
00879 
00880    // Count interations
00881    (hs->Iter)++;
00882 
00883    // Update time stamp
00884    hs->TimeStamp = time(0);
00885 
00886    // Local vars
00887    int nextstep = 0;
00888    const char *stepstr = 0;
00889    kXR_int32 status = 0;
00890    char *bpub = 0;
00891    int lpub = 0;
00892    String CryptList = "";
00893    String Host = "";
00894    String RemID = "";
00895    String Emsg;
00896    String specID = "";
00897    // Buffer / Bucket related
00898    XrdSutBucket *bck    = 0;
00899    XrdSutBuffer *bpar   = 0;  // Global buffer
00900    XrdSutBuffer *bmai   = 0;  // Main buffer
00901    // Session status
00902    pwdStatus_t   SessionSt;
00903    memset(&SessionSt,0,sizeof(SessionSt));
00904 
00905    //
00906    // Unlocks automatically returning
00907    XrdSysMutexHelper pwdGuard(&pwdContext);
00908    //
00909    // Decode received buffer
00910    bpar = hs->Parms;
00911    if (!bpar && !(bpar = new XrdSutBuffer((const char *)parm->buffer,parm->size)))
00912       return ErrC(ei,0,0,0,kPWErrDecodeBuffer,"global",stepstr);
00913    // Ownership has been transferred
00914    hs->Parms = 0;
00915    //
00916    // Check protocol ID name
00917    if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
00918       return ErrC(ei,bpar,bmai,0,kPWErrBadProtocol,stepstr);
00919    //
00920    // The step indicates what we are supposed to do
00921    hs->Step = (bpar->GetStep()) ? bpar->GetStep() : kXPS_init;
00922    stepstr = ServerStepStr(hs->Step);
00923    // Dump, if requested
00924    if (QTRACE(Authen)) {
00925       bpar->Dump(stepstr);
00926    }
00927    //
00928    // Find first crypto module to be used
00929    if (ParseCrypto(bpar) != 0)
00930       return ErrC(ei,bpar,0,0,kPWErrLoadCrypto,stepstr);
00931    //
00932    // Parse input buffer
00933    if (ParseClientInput(bpar, &bmai, Emsg) == -1) {
00934       DEBUG(Emsg);
00935       return ErrC(ei,bpar,bmai,0,kPWErrParseBuffer,Emsg.c_str(),stepstr);
00936    }
00937    //
00938    // Version
00939    DEBUG("version run by server: "<< hs->RemVers);
00940    //
00941    // Dump what we got
00942    if (QTRACE(Authen)) {
00943       bmai->Dump("Main IN");
00944    }
00945    //
00946    // Print server messages, if any
00947    if (hs->Iter > 1) {
00948       bmai->Message();
00949       bmai->Deactivate(kXRS_message);
00950    }
00951    //
00952    // Check random challenge
00953    if (!CheckRtag(bmai, Emsg))
00954       return ErrC(ei,bpar,bmai,0,kPWErrBadRndmTag,Emsg.c_str(),stepstr);
00955 
00956    //
00957    // Get the status bucket, if any
00958    if ((bck = bmai->GetBucket(kXRS_status))) {
00959       int pst = 0;
00960       memcpy(&pst,bck->buffer,sizeof(pwdStatus_t));
00961       pst = ntohl(pst);
00962       memcpy(&SessionSt, &pst, sizeof(pwdStatus_t));
00963       bmai->Deactivate(kXRS_status);
00964    } else {
00965       SessionSt.ctype = kpCT_normal;
00966    }
00967    //
00968    // Now action depens on the step
00969    nextstep = kXPC_none;
00970    switch (hs->Step) {
00971 
00972    case kXPS_init:
00973       //
00974       // Add bucket with cryptomod to the global list
00975       // (This must be always visible from now on)
00976       if (bpar->AddBucket(hs->CryptoMod,kXRS_cryptomod) != 0)
00977          return ErrC(ei,bpar,bmai,0,
00978               kPWErrCreateBucket,XrdSutBuckStr(kXRS_cryptomod),stepstr);
00979       //
00980       // Add bucket with our version to the main list
00981       if (bmai->MarshalBucket(kXRS_version,(kXR_int32)(Version)) != 0)
00982          return ErrC(ei,bpar,bmai,0, kPWErrCreateBucket,
00983                 XrdSutBuckStr(kXRS_version),"(main list)",stepstr);
00984       //
00985       // We set some options in the option field of a pwdStatus_t structure
00986       if (hs->Tty || (AutoLogin > 0))
00987          SessionSt.options = kOptsClntTty;
00988 
00989    case kXPS_puk:
00990       // After auto-reg request, server puk have been saved in ParseClientInput:
00991       // we need to start a full normal login now
00992 
00993       //
00994       // If we have a session cipher we extract the public part
00995       // and add to the main packet for transmission to server
00996       if (hs->Hcip) {
00997          //
00998          // Extract buffer with public info for the cipher agreement
00999          if (!(bpub = hs->Hcip->Public(lpub))) 
01000             return ErrC(ei,bpar,bmai,0,
01001                         kPWErrNoPublic,"session",stepstr);
01002          //
01003          // Add it to the global list
01004          if (bpar->UpdateBucket(bpub,lpub,kXRS_puk) != 0)
01005             return ErrC(ei,bpar,bmai,0, kPWErrAddBucket,
01006                         XrdSutBuckStr(kXRS_puk),"global",stepstr);
01007          SafeDelArray(bpub);
01008          //
01009          // If we are requiring server verification of puk ownership
01010          // we are done for this step
01011          if (VeriSrv == 1) {
01012             nextstep = kXPC_verifysrv;
01013             break;
01014          }
01015       }
01016 
01017    case kXPS_signedrtag:     // (after kXRC_verifysrv)
01018       //
01019       // Add the username
01020       if (hs->User.length()) {
01021          if (bmai->AddBucket(hs->User,kXRS_user) != 0)
01022             return ErrC(ei,bpar,bmai,0, kPWErrDuplicateBucket,
01023                         XrdSutBuckStr(kXRS_user),stepstr);
01024       } else
01025          return ErrC(ei,bpar,bmai,0, kPWErrNoUser,stepstr);
01026 
01027       //
01028       // If we do not have a session cipher, the only thing we can 
01029       // try is auto-registration
01030       if (!(hs->Hcip)) {
01031          nextstep = kXPC_autoreg;
01032          break;
01033       }
01034 
01035       //
01036       // Normal attempt: add credentials
01037       status = kpCT_normal;
01038       if (hs->SysPwd == 1)
01039          status = kpCT_crypt;
01040       if (hs->SysPwd == 2)
01041          status = kpCT_afs;
01042       if (!(bck = QueryCreds(bmai, (AutoLogin > 0), status)))
01043          return ErrC(ei,bpar,bmai,0, kPWErrQueryCreds,
01044                                      hs->Tag.c_str(),stepstr);
01045       bmai->AddBucket(bck);
01046       //
01047       // Tell the server we want to change the password, if so
01048       if (hs->Pent->status == kPFE_onetime)
01049          SessionSt.options |= kOptsChngPwd;
01050       //
01051       nextstep = kXPC_normal;
01052       break;
01053 
01054    case kXPS_credsreq:
01055       //
01056       // If this is not the first time, during the handshake, that
01057       // we query credentials, any save buffer must insufficient,
01058       // so invalidate it
01059       if (hs->Pent)
01060          hs->Pent->cnt = 1;
01061       //
01062       // Server requires additional credentials: the status bucket
01063       // tells us what she wants exactly
01064       status = SessionSt.ctype;
01065       if (!(bck = QueryCreds(bmai, 0, status)))
01066          return ErrC(ei,bpar,bmai,0, kPWErrQueryCreds,
01067                                      hs->Tag.c_str(),stepstr);
01068       bmai->AddBucket(bck);
01069       //
01070       nextstep = kXPC_creds;
01071       break;
01072 
01073    case kXPS_failure:
01074       //
01075       // Failure: invalidate cache
01076       hs->Pent->buf1.SetBuf();
01077       hs->Pent->buf2.SetBuf();
01078       //
01079       nextstep = kXPC_failureack;
01080       break;
01081 
01082    case kXPS_newpuk:
01083       //
01084       // New server puk have been saved in ParseClientInput: we
01085       // just need to sign the random tag
01086    case kXPS_rtag:
01087       //
01088       // Not much to do: the random tag is signed in AddSerialized 
01089       nextstep = kXPC_signedrtag;
01090       break;
01091 
01092    default:
01093       return ErrC(ei,bpar,bmai,0, kPWErrBadOpt,stepstr);
01094    }
01095    //
01096    // Add / Update status
01097    int *pst = (int *) new char[sizeof(pwdStatus_t)];
01098    memcpy(pst,&SessionSt,sizeof(pwdStatus_t));
01099    *pst = htonl(*pst);
01100    if (bmai->AddBucket((char *)pst,sizeof(pwdStatus_t), kXRS_status) != 0) {
01101       DEBUG("problems adding bucket kXRS_status");
01102    }
01103    //
01104    // Serialize and encrypt
01105    if (AddSerialized('c', nextstep, hs->ID,
01106                      bpar, bmai, kXRS_main, hs->Hcip) != 0)
01107       return ErrC(ei,bpar,bmai,0,
01108                   kPWErrSerialBuffer,"main",stepstr);
01109    //
01110    // Serialize the global buffer
01111    char *bser = 0;
01112    int nser = bpar->Serialized(&bser,'f');
01113 
01114    if (QTRACE(Authen)) {
01115       bpar->Dump(ClientStepStr(bpar->GetStep()));
01116       bmai->Dump("Main OUT");
01117    }
01118    //
01119    // We may release the buffers now
01120    REL2(bpar,bmai);
01121    //
01122    // Return serialized buffer
01123    if (nser > 0) {
01124       DEBUG("returned " << nser <<" bytes of credentials");
01125       return new XrdSecCredentials(bser, nser);
01126    } else {
01127       DEBUG("problems with final serialization");
01128       return (XrdSecCredentials *)0;
01129    }
01130 }
01131 
01132 /******************************************************************************/
01133 /*               S e r v e r   O r i e n t e d   M e t h o d s                */
01134 /******************************************************************************/
01135 /******************************************************************************/
01136 /*                          A u t h e n t i c a t e                           */
01137 /******************************************************************************/
01138 
01139 int XrdSecProtocolpwd::Authenticate(XrdSecCredentials *cred,
01140                                     XrdSecParameters **parms,
01141                                     XrdOucErrInfo     *ei)
01142 {
01143    //
01144    // Check if we have any credentials or if no credentials really needed.
01145    // In either case, use host name as client name
01146    EPNAME("Authenticate");
01147 
01148    //
01149    // If cred buffer is two small or empty assume host protocol
01150    if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer) {
01151       strncpy(Entity.prot, "host", sizeof(Entity.prot));
01152       return 0;
01153    }
01154 
01155    // Handshake vars container must be initialized at this point
01156    if (!hs)
01157       return ErrS(String("none"),ei,0,0,0,kPWErrError,
01158                   "handshake var container missing",
01159                   "protocol initialization problems");
01160    hs->ErrMsg = "";
01161    //
01162    // Update time stamp
01163    hs->TimeStamp = time(0);
01164 
01165    //
01166    // ID of this handshaking
01167    hs->ID = Entity.tident;
01168    DEBUG("handshaking ID: " << hs->ID);
01169 
01170    // Local vars 
01171    int i = 0;
01172    int kS_rc = kpST_more;
01173    int rc = 0;
01174    int entst = 0;
01175    int nextstep = 0;
01176    int ctype = kpCT_normal;
01177    char *bpub = 0, *bpid = 0;
01178    int lpub = 0;
01179    const char *stepstr = 0;
01180    String Message;
01181    String CryptList;
01182    String Host;
01183    String SrvPuKExp;
01184    String Salt;
01185    String RndmTag;
01186    String ClntMsg(256);
01187    // Buffer related
01188    XrdSutBuffer    *bpar = 0;  // Global buffer
01189    XrdSutBuffer    *bmai = 0;  // Main buffer
01190    XrdSutBucket    *bck  = 0;  // Generic bucket
01191    // The local status info
01192    pwdStatus_t      SessionSt = { 0, 0, 0};
01193 
01194    //
01195    // Unlocks automatically returning
01196    XrdSysMutexHelper pwdGuard(&pwdContext);
01197    //
01198    // Decode received buffer
01199    if (!(bpar = new XrdSutBuffer((const char *)cred->buffer,cred->size)))
01200       return ErrS(hs->ID,ei,0,0,0,kPWErrDecodeBuffer,"global",stepstr);
01201    //
01202    // Check protocol ID name
01203    if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
01204       return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadProtocol,stepstr);
01205    //
01206    // The step indicates what we are supposed to do
01207    hs->Step = bpar->GetStep();
01208    stepstr = ClientStepStr(hs->Step);
01209    // Dump, if requested
01210    if (QTRACE(Authen)) {
01211       bpar->Dump(stepstr);
01212    }
01213 
01214    //
01215    // Find first crypto module to be used
01216    if (ParseCrypto(bpar) != 0)
01217       return ErrS(hs->ID,ei,bpar,0,0,kPWErrLoadCrypto,stepstr);
01218    //
01219    // Parse input buffer
01220    if (ParseServerInput(bpar, &bmai, ClntMsg) == -1) {
01221       DEBUG(ClntMsg);
01222       return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrParseBuffer,ClntMsg.c_str(),stepstr);
01223    }
01224    //
01225    // Get handshake status
01226    if ((bck = bmai->GetBucket(kXRS_status))) {
01227       int pst = 0;
01228       memcpy(&pst,bck->buffer,sizeof(pwdStatus_t));
01229       pst = ntohl(pst);
01230       memcpy(&SessionSt, &pst, sizeof(pwdStatus_t));
01231       bmai->Deactivate(kXRS_status);
01232    } else {
01233       DEBUG("no bucket kXRS_status found in main buffer");
01234    }   
01235    hs->Tty = SessionSt.options & kOptsClntTty;
01236    //
01237    // Client name
01238    unsigned int ulen = hs->User.length();
01239    ulen = (ulen > sizeof(CName)-1) ? sizeof(CName)-1 : ulen; 
01240    if (ulen)
01241       strcpy(CName, hs->User.c_str());
01242    // And set link to entity
01243    Entity.name = strdup(CName);
01244 
01245    //
01246    // Version
01247    DEBUG("version run by client: "<< hs->RemVers);
01248    //
01249    // Dump, if requested
01250    if (QTRACE(Authen)) {
01251       bmai->Dump("main IN");
01252    }
01253    //
01254    // Check random challenge
01255    if (!CheckRtag(bmai, ClntMsg))
01256       return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadRndmTag,stepstr,ClntMsg.c_str());
01257    //
01258    // Check also host / time stamp (it will be done only if really neede)
01259    if (!CheckTimeStamp(bmai, TimeSkew, ClntMsg))
01260       return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadRndmTag,stepstr,ClntMsg.c_str());
01261    //
01262    // Now action depens on the step
01263    bool savecreds = (SessionSt.options & kOptsExpCred);
01264    switch (hs->Step) {
01265 
01266    case kXPC_verifysrv:
01267       //
01268       // Client required us to sign a random challenge: this is done
01269       // in AddSerialized, so nothing to do here
01270       nextstep = kXPS_signedrtag;
01271       break;
01272 
01273    case kXPC_signedrtag:
01274       //
01275       // Client signed the random challenge we sent: if we are here,
01276       // everything was fine
01277       kS_rc = kpST_ok;
01278       nextstep = kXPS_none;
01279       break;
01280 
01281    case kXPC_failureack:
01282       //
01283       // Client acknowledged failure
01284       kS_rc = kpST_error;
01285       nextstep = kXPS_none;
01286       break;
01287 
01288    case kXPC_autoreg:
01289       //
01290       // Client has lost the key or requested auto-registration: we
01291       // check the username: if it has a good entry or it is allowed
01292       // to auto-register (the check is done in QueryUser) we send
01293       // the public part of the key; otherwise we fail
01294       rc = QueryUser(entst, ClntMsg);
01295       if (rc < 0 || (entst == kPFE_disabled))
01296          return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
01297                      DefError.c_str(),stepstr);
01298       //
01299       // We have to send the public key
01300       for (i = 0; i < ncrypt; i++) {
01301          if (refcip[i]) {
01302             //
01303             // Extract buffer with public info for the cipher agreement
01304             if (!(bpub = refcip[i]->Public(lpub))) 
01305                return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrNoPublic,
01306                                                "session",stepstr);
01307             bpid = new char[lpub+5];
01308             if (bpid) {
01309                char cid[5] = {0};
01310                sprintf(cid,"%d",cryptID[i]);
01311                memcpy(bpid,cid,5);
01312                memcpy(bpid+5, bpub, lpub);
01313                //
01314                // Add it to the global list
01315                if (bmai->AddBucket(bpid,lpub+5,kXRS_puk) != 0)
01316                   return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrAddBucket,
01317                                                   "main",stepstr);
01318             } else 
01319                return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrError,
01320                                              "out-of-memory",stepstr);
01321             SafeDelArray(bpub); // bpid is taken by the bucket
01322          }
01323       }
01324       // client should now go through a complete login
01325       nextstep = kXPS_puk;
01326       break;
01327 
01328    case kXPC_normal:
01329       //
01330       // Complete login sequence: check user and creds
01331       if (QueryUser(entst,ClntMsg) != 0)
01332          return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
01333                      ": user ",hs->User.c_str(),stepstr);
01334       // Nothing to do, if disabled
01335       if (entst == kPFE_disabled)
01336          return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
01337                      ": user ",hs->User.c_str(),stepstr);
01338 
01339       if (entst == kPFE_expired || entst == kPFE_onetime) {
01340          // New credentials should asked upon success first check
01341          SessionSt.options |= kOptsExpCred;
01342       }
01343       if (entst == kPFE_crypt) {
01344          // User credentials are either in crypt form (private or
01345          // system ones) or of AFS type; in case of failure
01346          // this flag allows the client to send the right creds
01347          // at next iteration
01348          if (ClntMsg.beginswith("afs:")) {
01349             SessionSt.options |= kOptsAFSPwd;
01350          } else
01351             SessionSt.options |= kOptsCrypPwd;
01352          // Reset the message
01353          ClntMsg = "";
01354       }
01355       // Creds, if any, should be checked, unles we allow auto-registration
01356       savecreds = (entst != kPFE_allowed) ? 0 : 1;
01357 
01358    case kXPC_creds:
01359       //
01360       // Final login sequence: extract and check creds
01361       // Extract credentials from main buffer
01362       if (!(bck = bmai->GetBucket(kXRS_creds))) {
01363          //
01364          // If credentials are missing, require them
01365          kS_rc = kpST_more;
01366          nextstep = kXPS_credsreq;
01367          break;
01368       }
01369       //
01370       // If we required new credentials at previous step, just save them
01371       if (savecreds) {
01372          if (SaveCreds(bck) != 0) {
01373             ClntMsg = "Warning: could not correctly update credentials database"; 
01374          }
01375          kS_rc = kpST_ok;
01376          nextstep = kXPS_none;
01377          bmai->Deactivate(kXRS_creds);
01378          break;
01379       }
01380       //
01381       // Credential type
01382       ctype = kpCT_normal;
01383       if (SessionSt.options & kOptsCrypPwd)
01384          ctype = kpCT_crypt;
01385       else if (SessionSt.options & kOptsAFSPwd) {
01386          ctype = kpCT_afs;
01387          String afsInfo;
01388          XrdSutBucket *bafs = bmai->GetBucket(kXRS_afsinfo);
01389          if (bafs)
01390             bafs->ToString(afsInfo);
01391          if (afsInfo == "c")
01392             ctype = kpCT_afsenc;
01393       }
01394       //
01395       // Check credentials
01396       if (!CheckCreds(bck, ctype)) {
01397          //
01398          // Count temporary failures
01399          (hs->Cref->cnt)++;
01400          // Reset expired credentials flag
01401          SessionSt.options &= ~kOptsExpCred;
01402          // Repeat if not too many attempts
01403          ClntMsg = DefError;
01404          if (hs->Cref->cnt < MaxPrompts) {
01405             // Set next step to credential request
01406             nextstep = kXPS_credsreq;
01407             kS_rc = kpST_more;
01408             // request again creds
01409             if (hs->Pent->status == kPFE_crypt) {
01410                SessionSt.ctype = kpCT_crypt;
01411                if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
01412                   SessionSt.ctype = kpCT_afs;
01413                   String afsinfo = hs->ErrMsg;
01414                   bmai->UpdateBucket(afsinfo, kXRS_afsinfo);
01415                }
01416                ClntMsg = "";
01417             } else {
01418                SessionSt.ctype = kpCT_normal;
01419                ClntMsg = "insufficient credentials";
01420             }
01421          } else {
01422             // We communicate failure
01423             kS_rc = kpST_more;
01424             nextstep = kXPS_failure;
01425             // Count failures
01426             (hs->Pent->cnt)++;
01427             // Count failures
01428             hs->Pent->mtime = (kXR_int32)time(0);
01429             // Flush cache content to source file
01430             XrdSysPrivGuard priv(getuid(), getgid());
01431             if (priv.Valid()) {
01432                if (cacheAdmin.Flush() != 0) {
01433                   DEBUG("WARNING: some problem flushing to admin"
01434                         " file after updating "<<hs->Pent->name);
01435                }
01436             }
01437          }
01438       } else {
01439          // Reset counter for temporary failures
01440          hs->Cref->cnt = 0;
01441          // Reset counter in file if needed
01442          if (hs->Pent->cnt > 0) {
01443             hs->Pent->cnt = 0;
01444             // Count failures
01445             hs->Pent->mtime = (kXR_int32)time(0);
01446             // Flush cache content to source file
01447             XrdSysPrivGuard priv(getuid(), getgid());
01448             if (priv.Valid()) {
01449                if (cacheAdmin.Flush() != 0) {
01450                   DEBUG("WARNING: some problem flushing to admin"
01451                         " file after updating "<<hs->Pent->name);
01452                }
01453             }
01454          }
01455          kS_rc = kpST_ok;
01456          nextstep = kXPS_none;
01457          if (SessionSt.options & kOptsExpCred ||
01458              // Client requested a pwd change
01459              SessionSt.options & kOptsChngPwd) {
01460             kS_rc = kpST_more;
01461             nextstep = kXPS_credsreq;
01462             if (SessionSt.options & kOptsExpCred) {
01463                ClntMsg = "Credentials expired";
01464             } else if (SessionSt.options & kOptsChngPwd) {
01465                ClntMsg = "Password change requested";
01466             }
01467             // request new creds
01468             SessionSt.ctype = kpCT_new;
01469             // So we can save at next round
01470             SessionSt.options |= kOptsExpCred;
01471          }
01472          // Create buffer to keep the credentials, if required
01473          if (KeepCreds) {
01474             int sz = bck->size+5;
01475             char *buf = (char *) malloc(sz);
01476             if (buf) {
01477                memcpy(buf, "&pwd", 4);
01478                buf[4] = 0;
01479                memcpy(buf+5, bck->buffer, bck->size);
01480                // Put in hex
01481                char *out = new char[2*sz+1];
01482                XrdSutToHex(buf, sz, out);
01483                // Cleanup any existing info
01484                SafeDelete(clientCreds);
01485                clientCreds = new XrdSecCredentials(out, 2*sz+1);
01486             }
01487          }
01488          // Export creds to a file, if required
01489          if (FileExpCreds.length() > 0) {
01490             if (ExportCreds(bck) != 0)
01491                DEBUG("WARNING: some problem exporting creds to file;"
01492                      " template is :"<<FileExpCreds);
01493          }
01494       }
01495       // We will not use again these credentials
01496       bmai->Deactivate(kXRS_creds);
01497 
01498       break;
01499 
01500    default:
01501       return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadOpt, stepstr);
01502    }
01503 
01504    //
01505    // If strong signature checking is required add random tag
01506    if (kS_rc == kpST_ok) {
01507       if (VeriClnt == 2 && !(hs->RtagOK)) {
01508          // Send only the random tag to sign
01509          nextstep = kXPS_rtag;
01510          kS_rc = kpST_more;
01511       }
01512    }
01513 
01514    //
01515    // If we need additional info but the client caa not reply, just fail
01516    if (kS_rc == kpST_more && !(hs->Tty)) {
01517       DEBUG("client cannot reply to additional request: failure");
01518       // Deactivate everything
01519       bpar->Deactivate(-1);
01520       bmai->Deactivate(-1);
01521       kS_rc = kpST_error;
01522    }
01523    //
01524    if (kS_rc == kpST_more) {
01525       //
01526       // Add message to client
01527       if (ClntMsg.length() > 0)
01528          if (bmai->AddBucket(ClntMsg,kXRS_message) != 0) {
01529             DEBUG("problems adding bucket with message for client");
01530          }
01531       //
01532       // We set some options in the option field of a pwdStatus_t structure
01533       int *pst = (int *) new char[sizeof(pwdStatus_t)];
01534       memcpy(pst,&SessionSt,sizeof(pwdStatus_t));
01535       *pst = htonl(*pst);
01536       if (bmai->AddBucket((char *)pst,sizeof(pwdStatus_t), kXRS_status) != 0) {
01537          DEBUG("problems adding bucket kXRS_status");
01538       }
01539       //
01540       // Serialize, encrypt and add to the global list
01541       if (AddSerialized('s', nextstep, hs->ID,
01542                         bpar, bmai, kXRS_main, hs->Hcip) != 0)
01543          return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrSerialBuffer,
01544                      "main / session cipher",stepstr);
01545       //
01546       // Serialize the global buffer
01547       char *bser = 0;
01548       int nser = bpar->Serialized(&bser,'f');
01549       //
01550       // Dump, if requested
01551       if (QTRACE(Authen)) {
01552          bpar->Dump(ServerStepStr(bpar->GetStep()));
01553          bmai->Dump("Main OUT");
01554       }
01555       //
01556       // Create buffer for client
01557       *parms = new XrdSecParameters(bser,nser);
01558    } else {
01559       //
01560       // Cleanup handshake vars
01561       SafeDelete(hs);
01562    }
01563    //
01564    // We may release the buffers now
01565    REL2(bpar,bmai);
01566    //
01567    // All done
01568    return kS_rc;
01569 }
01570 
01571 /******************************************************************************/
01572 /*              X r d S e c P r o t o c o l p w d I n i t                     */
01573 /******************************************************************************/
01574   
01575 extern "C"
01576 {
01577 char *XrdSecProtocolpwdInit(const char mode,
01578                             const char *parms, XrdOucErrInfo *erp)
01579 {
01580    // One-time protocol initialization, filling the static flags and options
01581    // of the protocol.
01582    // For clients (mode == 'c') we use values in envs.
01583    // For servers (mode == 's') the command line options are passed through
01584    // parms.
01585    pwdOptions opts;
01586    char *rc = (char *)"";
01587    char *cenv = 0;
01588 
01589    //
01590    // Clients first
01591    if (mode == 'c') {
01592       //
01593       // Decode envs:
01594       //              "XrdSecDEBUG"          debug flag ("0","1","2","3")
01595       //              "XrdSecPWDVERIFYSRV"   "1" server verification ON [default]
01596       //                                     "0" server verification OFF
01597       //              "XrdSecPWDSRVPUK"      full path to file with server puks
01598       //                                     [default: $HOME/.xrd/pwdsrvpuk]
01599       //              "XrdSecPWDAUTOLOG"     "1" autologin ON [default]
01600       //                                     "0" autologin OFF
01601       //              "XrdSecPWDALOGFILE"    full path to file with autologin
01602       //                                     info [default: $HOME/.xrd/pwdnetrc]
01603       //              "XrdSecPWDALOGUPDT"    update autologin file option:
01604       //                                     "0"  never [default]
01605       //                                     "1"  remove_obsolete_info
01606       //                                     "2"  "1" + register_new_valid_info
01607       //              "XrdSecPWDMAXPROMPT"   max number of attemts to get valid
01608       //                                     input info by prompting the client
01609       //
01610       opts.mode = mode;
01611       // debug
01612       cenv = getenv("XrdSecDEBUG");
01613       if (cenv)
01614          if (cenv[0] >= 49 && cenv[0] <= 51) opts.debug = atoi(cenv);  
01615 
01616       // server verification
01617       cenv = getenv("XrdSecPWDVERIFYSRV");
01618       if (cenv)
01619          if (cenv[0] >= 48 && cenv[0] <= 49) opts.verisrv = atoi(cenv);  
01620       // file with server public keys
01621       cenv = getenv("XrdSecPWDSRVPUK");
01622       if (cenv)
01623          opts.srvpuk = strdup(cenv);  
01624       // autologin
01625       cenv = getenv("XrdSecPWDAUTOLOG");
01626       if (cenv)
01627          if (cenv[0] >= 48 && cenv[0] <= 50) opts.alog = atoi(cenv);  
01628       // autologin file
01629       cenv = getenv("XrdSecPWDALOGFILE");
01630       if (cenv)
01631          opts.alogfile = strdup(cenv);  
01632       // max re-prompts
01633       cenv = getenv("XrdSecPWDMAXPROMPT");
01634       if (cenv) {
01635          opts.maxprompts = strtol(cenv, (char **)0, 10);
01636          if (errno == ERANGE) opts.maxprompts = -1;
01637       }
01638       //
01639       // Setup the object with the chosen options
01640       rc = XrdSecProtocolpwd::Init(opts,erp);
01641 
01642       // Some cleanup
01643       if (opts.srvpuk) free(opts.srvpuk);
01644       if (opts.alogfile) free(opts.alogfile);
01645 
01646       // We are done
01647       return rc;
01648    }
01649 
01650    // Take into account xrootd debug flag
01651    cenv = getenv("XRDDEBUG");
01652    if (cenv && !strcmp(cenv,"1")) opts.debug = 1;
01653 
01654    //
01655    // Server initialization
01656    if (parms) {
01657       // 
01658       // Duplicate the parms
01659       char parmbuff[1024];
01660       strlcpy(parmbuff, parms, sizeof(parmbuff));
01661       //
01662       // The tokenizer
01663       XrdOucTokenizer inParms(parmbuff);
01664 
01665       //
01666       // Decode parms:
01667       // for servers: [-upwd:<user_pwd_option>]
01668       //              [-a:<autoreg_level>]
01669       //              [-vc:<client_verification_level>]
01670       //              [-dir:<dir_with_pwd_info>]
01671       //              [-udir:<sub_dir_with_user_pwd_info>]
01672       //              [-c:[-]ssl[:[-]<CryptoModuleName]]
01673       //              [-d:<debug_level>]
01674       //              [-syspwd]
01675       //              [-lf:<credential_lifetime>]
01676       //              [-maxfail:<max_number_of_failures>]
01677       //              [-keepcreds]
01678       //              [-expcreds:<creds_file_name>]
01679       //
01680       // <user_pwd_opt> = 0 (do-not-use), 1 (use), 2 (also-crypt-hash)
01681       // <debug_level> = 0 (none), 1 (low), 2 (medium), 3 (high)   [0]
01682       // <autoreg_level> = 0 (none), 1 (local users + allowed tags), 2 (all) [0]
01683       // <credential_lifetime> = 1d, 5h:10m, ... (see XrdSutAux::ParseTime)
01684       // <client_verification_level> = 0 (none), 1 (timestamp), 2 (random tag) [2]
01685       // <creds_file_name> = can be a fully specified path or in the templated form
01686       //                     /path/<user>/file, with <user> expanded at the moment
01687       //                     of use with the login name.
01688       //
01689       int debug = -1;
01690       int areg = -1;
01691       int vc = -1;
01692       int upw = -1;
01693       int syspwd = -1;
01694       int lifetime = -1;
01695       int maxfail = -1;
01696       String dir = "";
01697       String udir = "";
01698       String clist = "";
01699       String cpass = "";
01700       int keepcreds = -1;
01701       String expcreds = "";
01702       char *op = 0;
01703       while (inParms.GetLine()) { 
01704          while ((op = inParms.GetToken())) {
01705             if (!strncmp(op, "-upwd:",6)) {
01706                upw = atoi(op+6);
01707             } else if (!strncmp(op, "-dir:",5)) {
01708                dir = (const char *)(op+5);
01709             } else if (!strncmp(op, "-udir:",6)) {
01710                udir = (const char *)(op+6);
01711             } else if (!strncmp(op, "-c:",3)) {
01712                clist = (const char *)(op+3);
01713             } else if (!strncmp(op, "-d:",3)) {
01714                debug = atoi(op+3);
01715             } else if (!strncmp(op, "-a:",3)) {
01716                areg = atoi(op+3);
01717             } else if (!strncmp(op, "-vc:",4)) {
01718                vc = atoi(op+4);
01719             } else if (!strncmp(op, "-syspwd",7)) {
01720                syspwd = 1;
01721             } else if (!strncmp(op, "-lf:",4)) {
01722                lifetime = XrdSutParseTime(op+4);
01723             } else if (!strncmp(op, "-maxfail:",9)) {
01724                maxfail =  atoi(op+9);
01725             } else if (!strncmp(op, "-cryptfile:",11)) {
01726                cpass = (const char *)(op+11);
01727             } else if (!strncmp(op, "-keepcreds",10)) {
01728                keepcreds = 1;
01729             } else if (!strncmp(op, "-expcreds:",10)) {
01730                expcreds = (const char *)(op+10);
01731             }
01732          }
01733          // Check inputs
01734          areg = (areg >= 0 && areg <= 2) ? areg : 0;
01735          vc = (vc >= 0 && vc <= 2) ? vc : 2;
01736       }
01737 
01738       //
01739       // Build the option object
01740       opts.debug = (debug > -1) ? debug : opts.debug;
01741       opts.mode = 's';
01742       opts.areg = areg;
01743       opts.vericlnt = vc;
01744       opts.upwd = upw;
01745       opts.syspwd = syspwd;
01746       opts.lifecreds = lifetime;
01747       opts.maxfailures = maxfail;
01748       if (dir.length() > 0)
01749          opts.dir = (char *)dir.c_str();
01750       if (udir.length() > 0)
01751          opts.udir = (char *)udir.c_str();
01752       if (clist.length() > 0)
01753          opts.clist = (char *)clist.c_str();
01754       if (cpass.length() > 0)
01755          opts.cpass = (char *)cpass.c_str();
01756       opts.keepcreds = keepcreds;
01757       if (expcreds.length() > 0)
01758          opts.expcreds = (char *)expcreds.c_str();
01759       //
01760       // Setup the plug-in with the chosen options
01761       return XrdSecProtocolpwd::Init(opts,erp);
01762    }
01763    //
01764    // Setup the plug-in with the defaults
01765    return XrdSecProtocolpwd::Init(opts,erp);
01766 }}
01767 
01768 
01769 /******************************************************************************/
01770 /*              X r d S e c P r o t o c o l p w d O b j e c t                 */
01771 /******************************************************************************/
01772   
01773 extern "C"
01774 {
01775 XrdSecProtocol *XrdSecProtocolpwdObject(const char              mode,
01776                                         const char             *hostname,
01777                                         const struct sockaddr  &netaddr,
01778                                         const char             *parms,
01779                                         XrdOucErrInfo    *erp)
01780 {
01781    XrdSecProtocolpwd *prot;
01782    int options = XrdSecNOIPCHK;
01783 
01784    //
01785    // Get a new protocol object
01786    if (!(prot = new XrdSecProtocolpwd(options, hostname, &netaddr, parms))) {
01787       char *msg = (char *)"Secpwd: Insufficient memory for protocol.";
01788       if (erp) 
01789          erp->setErrInfo(ENOMEM, msg);
01790       else 
01791          cerr <<msg <<endl;
01792       return (XrdSecProtocol *)0;
01793    }
01794    //
01795    // We are done
01796    if (!erp)
01797       cerr << "protocol object instantiated" << endl;
01798    return prot;
01799 }}
01800 
01801  
01802 /******************************************************************************/
01803 /*                       P r i v a t e   M e t h o d s                        */
01804 /******************************************************************************/
01805 
01806 //__________________________________________________________________________
01807 int XrdSecProtocolpwd::ParseCrypto(XrdSutBuffer *buf)
01808 {
01809    // Parse received buffer for the crypto module to be used.
01810    // Parse crypto list clist, extracting the first available module
01811    // and getting a related local cipher and a related reference
01812    // cipher to be used to agree the session cipher; the local lists
01813    // crypto info is updated, if needed
01814    // The results are used to fill the handshake part of the protocol
01815    // instance.
01816    EPNAME("ParseCrypto");
01817 
01818    // Check inputs
01819    if (!buf) {
01820       DEBUG("invalid input ("<<buf<<")");
01821       return -1;
01822    }
01823 
01824    String clist = "";
01825    XrdSutBucket *bck = 0;
01826    // Check type of buffer we got
01827    if (!buf->GetNBuckets()) {
01828       // If the bucket list is empty we assume this being the first iteration
01829       // step (the step is not defined at this point).
01830       // The option field should contain the relevant information
01831       String opts = buf->GetOptions();
01832       if (!(opts.length())) {
01833          DEBUG("missing options - bad format");
01834          return -1;
01835       }
01836       //
01837       // Extract crypto module list, if any
01838       int ii = opts.find("c:");
01839       if (ii >= 0) {
01840          clist.assign(opts, ii+2);
01841          clist.erase(clist.find(','));
01842       } else {
01843          DEBUG("crypto information not found in options");
01844          return -1;
01845       }
01846    } else {
01847       //
01848       // Extract crypto module name from the buffer
01849       if (!(bck = buf->GetBucket(kXRS_cryptomod))) {
01850          DEBUG("cryptomod buffer missing");
01851          return -1;
01852       }
01853       bck->ToString(clist);
01854    }
01855    DEBUG("parsing list: "<<clist.c_str());
01856  
01857    // Load module and define relevant pointers
01858    hs->CryptoMod = "";
01859    // Parse list
01860    if (clist.length()) {
01861       int from = 0;
01862       while ((from = clist.tokenize(hs->CryptoMod, from, '|')) != -1) {
01863          // Check this module
01864          if (hs->CryptoMod.length()) {
01865             // Load the crypto factory
01866             if ((hs->CF = XrdCryptoFactory::GetCryptoFactory(hs->CryptoMod.c_str()))) {
01867                int fid = hs->CF->ID();
01868                int i = 0;
01869                // Retrieve the index in local table
01870                while (i < ncrypt) {
01871                   if (cryptID[i] == fid) break;
01872                   i++;
01873                }
01874                if (i >= ncrypt) {
01875                   if (ncrypt == XrdCryptoMax) {
01876                      DEBUG("max number of crypto slots reached - do nothing");
01877                      return 0;
01878                   } else {
01879                      // Add new entry
01880                      cryptID[i] = fid;
01881                      ncrypt++;
01882                   }
01883                }
01884                // On servers the ref cipher should be defined at this point
01885                hs->Rcip = refcip[i];
01886                // we are done
01887                return 0;
01888             }
01889          }
01890       }
01891    }
01892 
01893    return 1;
01894 }
01895 
01896 //____________________________________________________________________
01897 bool XrdSecProtocolpwd::CheckCreds(XrdSutBucket *creds, int ctype)
01898 {
01899    // Check credentials against information in password file
01900    EPNAME("CheckCreds");
01901    bool match = 0;
01902  
01903    // Check inputs
01904    if (!hs->CF || !creds || !hs->Pent) {
01905       DEBUG("Invalid inputs ("<<hs->CF<<","<<creds<<","<<hs->Pent<<")");
01906       return match;
01907    }
01908    // Make sure there is something to check against
01909    if (ctype != kpCT_afs && ctype != kpCT_afsenc &&
01910       (!(hs->Pent->buf1.buf) || hs->Pent->buf1.len <= 0)) {
01911       DEBUG("Cached information about creds missing");
01912       return match;
01913    }
01914    //
01915    // Create a buffer to store credentials, if required
01916    int len = creds->size+4;
01917    char *cbuf = (KeepCreds) ? new char[len] : (char *)0;
01918 
01919    //
01920    // Separate treatment for crypt-like creds
01921    if (ctype != kpCT_crypt && ctype != kpCT_afs && ctype != kpCT_afsenc) {
01922       //
01923       // Create a bucket for the salt to easy encryption
01924       XrdSutBucket *tmps = new XrdSutBucket();
01925       if (!tmps) {
01926          DEBUG("Could not allocate working buckets area for the salt");
01927          return match;
01928       }
01929       tmps->SetBuf(hs->Pent->buf1.buf, hs->Pent->buf1.len);
01930       //
01931       // Save input bucket if creds have to be kept
01932       if (KeepCreds) {
01933          memcpy(cbuf, "pwd:", 4);
01934          memcpy(cbuf+4, creds->buffer, creds->size);
01935       }
01936       //
01937       // Hash received buffer for the comparison
01938       DoubleHash(hs->CF,creds,tmps);
01939       // Compare
01940       if (hs->Pent->buf2.len == creds->size)
01941          if (!memcmp(creds->buffer, hs->Pent->buf2.buf, creds->size))
01942             match = 1;
01943       SafeDelete(tmps);
01944       //
01945       // recover input creds
01946       if (match && KeepCreds)
01947          creds->SetBuf(cbuf, len);
01948 
01949    } else {
01950 #ifndef DONT_HAVE_CRYPT
01951 #ifndef R__AFS
01952       // Crypt-like: get the pwhash
01953       String passwd(creds->buffer,creds->size+1);
01954       passwd.reset(0,creds->size,creds->size);
01955       // Get the crypt
01956       char *pass_crypt = crypt(passwd.c_str(), hs->Pent->buf1.buf);
01957       // Compare
01958       if (!strncmp(pass_crypt, hs->Pent->buf1.buf, hs->Pent->buf1.len + 1) != 0)
01959          match = 1;
01960       if (match && KeepCreds) {
01961          memcpy(cbuf, "cpt:", 4);
01962          memcpy(cbuf+4, creds->buffer, creds->size);
01963          creds->SetBuf(cbuf, len);
01964       }
01965 #else
01966       // Check the AFS credentials
01967       match = CheckCredsAFS(creds, ctype);
01968 #endif
01969 #else
01970       DEBUG("Crypt-like passwords (via crypt(...)) not supported");
01971       match = 0;
01972 #endif
01973    }
01974 
01975    // Cleanup
01976    if (cbuf)
01977       delete[] cbuf;
01978 
01979    // We are done
01980    return match;
01981 }
01982 
01983 #ifdef R__AFS
01984 //________________________________________________________________________
01985 bool XrdSecProtocolpwd::CheckCredsAFS(XrdSutBucket *creds, int ctype)
01986 {
01987    // Check AFS credentials, either in plain (ctype==kpCT_afs) or
01988    // encrypted (ctype==kpCT_afsenc) form
01989    EPNAME("CheckCredsAFS");
01990    bool match = 0;
01991    int rc = 0;
01992 
01993    // Here we are interested to the minimal token length (5 min)
01994    int life = 60;
01995 
01996    // We need a link to the user name
01997    char *usr = (char *) hs->User.c_str();
01998 
01999    bool notify = ((hs->Step == kXPC_creds) || QTRACE(ALL)) ? 1 : 0;
02000    struct ktc_encryptionKey key;
02001    if (ctype == kpCT_afs) {
02002       char *errmsg;
02003       char *pwd = new char[creds->size + 1];
02004       memcpy(pwd, creds->buffer, creds->size);
02005       pwd[creds->size] = 0;
02006       rc = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
02007                                       usr, (char *)"", (char *)"", pwd,
02008                                       life, 0, 0, &errmsg);
02009       if (rc) {
02010          if (notify)
02011             PRINT("CheckAFS: failure: "<< errmsg);
02012          hs->ErrMsg += ka_LocalCell();
02013       } else {
02014          match = 1;
02015          if (KeepCreds)
02016             // We need to encrypt te plain passwd
02017             ka_StringToKey(pwd, 0, &key);
02018          if (QTRACE(ALL))
02019             PRINT("CheckAFS: success!");
02020       }
02021       if (pwd) delete [] pwd;
02022 
02023    } else if (ctype == kpCT_afsenc) {
02024 
02025       // Get the cell
02026       char *cell = 0;
02027       char cellname[MAXKTCREALMLEN];
02028       if (ka_ExpandCell(cell, cellname, 0) != 0) {
02029          PRINT("CheckAFS: failure expanding cell");
02030          return match;
02031       }
02032       cell = cellname;
02033 
02034       // Get an unauthenticated connection to desired cell 
02035       struct ubik_client *conn = 0;
02036       if (ka_AuthServerConn(cell, KA_AUTHENTICATION_SERVICE, 0, &conn) != 0) {
02037          PRINT("CheckAFS: failure getting an unauthenticated connection to the cell");
02038          return match;
02039       }
02040 
02041       // Authenticate now
02042       memcpy(key.data, creds->buffer, creds->size);
02043       struct ktc_token token;
02044       int pwexpires;
02045       int now = hs->TimeStamp;
02046       rc = ka_Authenticate(usr, (char *)"", cell, conn,
02047                            KA_TICKET_GRANTING_SERVICE,
02048                            &key, now, now + life,
02049                            &token, &pwexpires);
02050       if (rc) {
02051          if (notify)
02052             PRINT("CheckAFS: failure from ka_Authenticate");
02053          hs->ErrMsg += ka_LocalCell();
02054       } else {
02055          match = 1;
02056          if (QTRACE(ALL))
02057             PRINT("CheckAFS: success!");
02058       }
02059    } else {
02060       PRINT("CheckAFS: unknown credential type: "<< ctype);
02061    }
02062 
02063    // Save the creds, if requested
02064    if (match && KeepCreds) {
02065       // Create new buffer
02066       int len = strlen("afs:") + 8;
02067       char *buf = new char[len];
02068       memcpy(buf,"afs:",4);
02069       memcpy(buf+4,key.data,8);
02070       // Fill output
02071       creds->SetBuf(buf,len);
02072    }
02073    // We are done
02074    return match;
02075 }
02076 #else
02077 //________________________________________________________________________
02078 bool XrdSecProtocolpwd::CheckCredsAFS(XrdSutBucket *, int)
02079 {
02080    // Check AFS credentials - not supported
02081    return 0;
02082 }
02083 #endif
02084 
02085 //____________________________________________________________________
02086 int XrdSecProtocolpwd::SaveCreds(XrdSutBucket *creds)
02087 {
02088    // Save credentials in creds in the password file
02089    // Returns 0 if ok, -1 otherwise
02090    EPNAME("SaveCreds");
02091 
02092    // Check inputs
02093    if ((hs->User.length() <= 0) || !hs->CF || !creds) {
02094       DEBUG("Bad inputs ("<<hs->User.length()<<","<<hs->CF<<","
02095                           <<creds<<")");
02096       return -1;
02097    }
02098    // Build effective tag
02099    String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
02100    //
02101    // Update entry in cache, if there, or add one
02102    XrdSutPFEntry *cent = cacheAdmin.Add(wTag.c_str());
02103    if (!cent) {
02104       DEBUG("Could not get entry in cache");
02105       return -1;
02106    }
02107    // Generate a salt and fill it in
02108    char *tmps = XrdSutRndm::GetBuffer(8,3);
02109    if (!tmps) {
02110       DEBUG("Could not generate salt: out-of-memory");
02111       return -1;
02112    }
02113    XrdSutBucket *salt = new XrdSutBucket(tmps,8);
02114    if (!salt) {
02115       DEBUG("Could not create salt bucket");
02116       return -1;
02117    }
02118    cent->buf1.SetBuf(salt->buffer,salt->size);
02119    //
02120    // Now we sign the creds with the salt
02121    DoubleHash(hs->CF,creds,salt);
02122    // and fill in the creds
02123    cent->buf2.SetBuf(creds->buffer,creds->size);
02124    //
02125    // Set entry status OK
02126    cent->status = kPFE_ok;
02127    //
02128    // Save entry
02129    cent->mtime = hs->TimeStamp;
02130    //
02131    DEBUG("Entry for tag: "<<wTag<<" updated in cache");
02132    //
02133    // Flush cache content to source file
02134    XrdSysPrivGuard priv(getuid(), getgid());
02135    if (priv.Valid()) {
02136       if (cacheAdmin.Flush() != 0) {
02137          DEBUG("WARNING: some problem flushing to admin file after updating "<<wTag);
02138       }
02139    }
02140    //
02141    // We are done
02142    return 0;
02143 }
02144 
02145 //____________________________________________________________________
02146 int XrdSecProtocolpwd::ExportCreds(XrdSutBucket *creds)
02147 {
02148    // Export client credentials to a PF file to be used as autologin
02149    // in a next step.
02150    // Returns 0 if ok, -1 otherwise
02151    EPNAME("ExportCreds");
02152 
02153    // Check inputs
02154    if ((hs->User.length() <= 0) || !hs->CF || !creds) {
02155       DEBUG("Bad inputs ("<<hs->User.length()<<","<<hs->CF<<","
02156                           <<creds<<")");
02157       return -1;
02158    }
02159 
02160    // Check inputs
02161    if (FileExpCreds.length() <= 0) {
02162       DEBUG("File (template) undefined - do nothing");
02163       return -1;
02164    }
02165 
02166    // Expand templated keywords, if needed
02167    String filecreds = FileExpCreds;
02168    // Resolve place-holders, if any
02169    if (XrdSutResolve(filecreds, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
02170       DEBUG("Problems resolving templates in "<<filecreds);
02171       return -1;
02172    }
02173    DEBUG("Exporting client creds to: "<<filecreds);
02174 
02175    // Attach or create the file
02176    XrdSutPFile pfcreds(filecreds.c_str());
02177    if (!pfcreds.IsValid()) {
02178       DEBUG("Problem attaching / creating file "<<filecreds);
02179       return -1;
02180    }
02181    //
02182    // Build effective tag
02183    String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
02184    //
02185    // Create and fill a new entry
02186    XrdSutPFEntry ent;
02187    ent.SetName(wTag.c_str());
02188    ent.status = kPFE_ok;
02189    ent.cnt    = 0;
02190    if (!strncmp(creds->buffer, "pwd:", 4)) {
02191       // Skip initial "pwd:"
02192       ent.buf1.SetBuf(creds->buffer+4, creds->size-4);
02193    } else {
02194       // For crypt and AFS we keep that to be able to distinguish
02195       // later on
02196       ent.buf1.SetBuf(creds->buffer,creds->size);
02197    }
02198    //
02199    // Write entry
02200    ent.mtime = time(0);
02201    pfcreds.WriteEntry(ent);
02202    DEBUG("New entry for "<<wTag<<" successfully written to file: "
02203                   <<filecreds);
02204    // We are done
02205    return 0;
02206 }
02207 
02208 //____________________________________________________________________
02209 XrdSutBucket *XrdSecProtocolpwd::QueryCreds(XrdSutBuffer *bm,
02210                                             bool netrc, int &status)
02211 {
02212    // Get credential information to be sent to the server
02213    EPNAME("QueryCreds");
02214 
02215    // Check inputs
02216    if (!bm || !hs->CF || hs->Tag.length() <= 0) {
02217       DEBUG("bad inputs ("<<bm<<","<<hs->CF<<","<<hs->Tag.length()<<")");
02218       return (XrdSutBucket *)0;
02219    }
02220 
02221    //
02222    // Type of creds (for the prompt)
02223    int ctype = (status > kpCT_undef) ? status : kpCT_normal;
02224    netrc = ((ctype == kpCT_normal || ctype == kpCT_onetime ||
02225              ctype == kpCT_old || ctype == kpCT_crypt)) ? netrc : 0;
02226    //
02227    // reset status
02228    status = kpCI_undef;
02229    // Output bucket
02230    XrdSutBucket *creds = new XrdSutBucket();
02231    if (!creds) {
02232       DEBUG("Could allocate bucket for creds");
02233       return (XrdSutBucket *)0;
02234    }
02235    creds->type = kXRS_creds;
02236 
02237    //
02238    // Build effective tag
02239    String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
02240 
02241    //
02242    // If creds are available in the environment pick them up and use them
02243    char *cf = 0;
02244    char *cbuf = getenv("XrdSecCREDS");
02245    if (cbuf) {
02246       int len = strlen(cbuf);
02247       // From hex
02248       int sz = len;
02249       char *out = new char[sz/2+2];
02250       XrdSutFromHex((const char *)cbuf, out, len);
02251       if ((cf = strstr(out, "&pwd"))) {
02252          cf += 5;
02253          len -= 5;
02254          if (len > 0) {
02255             // Get prefix
02256             char pfx[5] = {0};
02257             memcpy(pfx, cf, 4);
02258             cf += 4;
02259             len -= 4;
02260             if (len > 0) {
02261                DEBUG("using "<<len<<" bytes of creds from the environment; pfx: "<<pfx);
02262                // Create or Fill entry in cache
02263                hs->Pent = cacheAlog.Add(wTag.c_str());
02264                if (hs->Pent) {
02265                  // Try only once
02266                   if (hs->Pent->cnt == 0) {
02267                      // Set buf
02268                      creds->SetBuf(cf,len);
02269                      // Fill entry
02270                      if (strncmp(pfx,"pwd",3))
02271                         hs->Pent->status = kPFE_crypt;
02272                      hs->Pent->mtime = hs->TimeStamp;
02273                      hs->Pent->buf1.SetBuf(cf, len);
02274                      // Just in case we need the passwd itself (like in crypt)
02275                      hs->Pent->buf2.SetBuf(cf, len);
02276                      // Tell the server
02277                      if (!strncmp(pfx,"afs",3)) {
02278                         String afsInfo = "c";
02279                         if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
02280                            PRINT("Warning: problems updating bucket with AFS info");
02281                      }
02282                      // Update status
02283                      status = kpCI_exact; 
02284                      // We are done
02285                      return creds;
02286                   } else {
02287                      // Cleanup
02288                      hs->Pent->buf1.SetBuf();
02289                      hs->Pent->buf2.SetBuf();
02290                   }
02291                } else {
02292                   PRINT("Could create new entry in cache");
02293                   return (XrdSutBucket *)0;
02294                }
02295             }
02296          }
02297       }
02298    }
02299 
02300    //
02301    // Extract AFS info (the cell), if any
02302    String afsInfo;
02303    if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
02304       XrdSutBucket *bafs = bm->GetBucket(kXRS_afsinfo);
02305       if (bafs)
02306          bafs->ToString(afsInfo);
02307    }
02308    //
02309    // Search information in autolog file(s) first, if required
02310    if (netrc) {
02311       //
02312       // Make sure cache it is up-to-date
02313       if (PFAlog.IsValid()) {
02314          if (cacheAlog.Refresh() != 0) {
02315             DEBUG("problems assuring cache update for file alog ");
02316          }
02317       }
02318       //
02319       // We may already have an entry in the cache
02320       bool wild = 0;
02321       hs->Pent = cacheAlog.Get(wTag.c_str(),&wild);
02322       // Retrieve pwd information if ok 
02323       if (hs->Pent && hs->Pent->buf1.buf) {
02324          if (hs->Pent->cnt == 0) {
02325             cf = hs->Pent->buf1.buf;
02326             bool afspwd = strncmp(cf,"afs",3) ? 0 : 1;
02327             if (!strncmp(cf,"cpt",3) || afspwd) {
02328                int len = hs->Pent->buf1.len;
02329                cf += 4;
02330                len -= 4;
02331                hs->Pent->status = kPFE_crypt;
02332                hs->Pent->mtime = hs->TimeStamp;
02333                hs->Pent->buf1.SetBuf(cf, len);
02334                // Just in case we need the passwd itself (like in crypt)
02335                hs->Pent->buf2.SetBuf(cf, len);
02336                // Tell the server
02337                if (afspwd) {
02338                   afsInfo = "c";
02339                   if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
02340                      PRINT("Warning: problems updating bucket with AFS info");
02341                }
02342             }
02343             // Fill output with double hash
02344             creds->SetBuf(hs->Pent->buf1.buf,hs->Pent->buf1.len);
02345             // Update status
02346             status = wild ? kpCI_wildcard : kpCI_exact; 
02347             // We are done
02348             return creds;
02349          } else {
02350             // Entry not ok: probably previous attempt failed: discard
02351             hs->Pent->buf1.SetBuf();
02352          }
02353       }
02354 
02355       // for crypt-like, look also into a .netrc-like file, if any
02356       String passwd;
02357       String host(hs->Tag,hs->Tag.find("@",0)+1,hs->Tag.find(":",0)-1);
02358       if (QueryNetRc(host, passwd, status) == 0) {
02359          // Create or Fill entry in cache
02360          if ((hs->Pent = cacheAlog.Add(wTag.c_str()))) {
02361             // Fill entry
02362             hs->Pent->status = kPFE_crypt;
02363             hs->Pent->mtime = hs->TimeStamp;
02364             hs->Pent->buf1.SetBuf(passwd.c_str(),passwd.length());
02365             // Fill output
02366             creds->SetBuf(passwd.c_str(),passwd.length());
02367             // Update status
02368             status = kpCI_exact; 
02369             // We are done
02370             return creds;
02371          } else {
02372             DEBUG("Could create new entry in cache");
02373             return (XrdSutBucket *)0;
02374          }
02375       }
02376    }
02377    //
02378    // Create or Fill entry in cache
02379    if (!(hs->Pent) && !(hs->Pent = cacheAlog.Add(wTag.c_str()))) {
02380       DEBUG("Could create new entry in cache");
02381       return (XrdSutBucket *)0;
02382    }
02383 
02384    //
02385    // If a previous attempt was successful re-use same passwd
02386    if (hs->Pent && hs->Pent->buf1.buf && hs->Pent->cnt == 0) {
02387       // Fill output
02388       creds->SetBuf(hs->Pent->buf1.buf,hs->Pent->buf1.len);
02389       // Update status
02390       status = kpCI_exact; 
02391       // We are done
02392       return creds;
02393    }
02394 
02395    //
02396    // We are here because:
02397    //   1) autologin disabled or no autologin info found
02398    //       ==> hs->Pent empty ==> prompt for password
02399    //   2) we need to send a new password hash because it was wrong
02400    //       ==> hs->Pent->buf2 empty ==> prompt for password
02401    //   3) we need to send a new password hash because it has expired
02402    //      (either one-time or too old)
02403    //       ==> query hs->Pent->buf2 before prompting
02404    //   4) we need to send a real password because the server uses crypt()
02405    //      or AFS
02406    //       ==> query hs->Pent->buf2 from previous prompt
02407 
02408    //
02409    // If the previously cached entry has a second (final) passwd
02410    // use it. This is the case when the real passwd is required (like in
02411    // crypt), we may have it in cache from a previous prompt
02412    if (ctype == kpCT_crypt || ctype == kpCT_afs) {
02413       if (hs->Pent && hs->Pent->buf2.buf) {
02414          if (ctype == kpCT_afs) {
02415 #ifdef R__AFS
02416             String passwd(hs->Pent->buf2.buf,hs->Pent->buf2.len);
02417             // We will send over and encrypted version
02418             struct ktc_encryptionKey key;
02419             ka_StringToKey((char *) passwd.c_str(),
02420                            (char *) afsInfo.c_str(), &key);
02421             // Fill output
02422             creds->SetBuf(key.data,8);
02423             // Tell the server
02424             afsInfo = "c";
02425             if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
02426                PRINT("Warning: problems updating bucket with AFS info");
02427 #else
02428             // Fill output
02429             creds->SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
02430             // Not needed anymore
02431             bm->Deactivate(kXRS_afsinfo);
02432 #endif
02433          } else {
02434             // Fill output
02435             creds->SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
02436          }
02437          // Save info in the first buffer and reset the second buffer
02438          hs->Pent->buf1.SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
02439          hs->Pent->buf2.SetBuf();
02440          // Update status
02441          status = kpCI_exact; 
02442          // We are done
02443          return creds;
02444       }
02445    }
02446 
02447    //
02448    // From now we need to prompt the user: we can do this only if
02449    // connected to a terminal
02450    if (!(hs->Tty)) {
02451       DEBUG("Not connected to tty: cannot prompt user for credentials");
02452       return (XrdSutBucket *)0;
02453    }
02454 
02455    //
02456    // Prompt
02457    char prompt[XrdSutMAXPPT] = {0};
02458    if (ctype == kpCT_onetime)
02459       snprintf(prompt,XrdSutMAXPPT, "Password for %s not active: "
02460                "starting activation handshake.",hs->Tag.c_str());
02461    //
02462    // Prepare the prompt
02463    if (ctype == kpCT_new) {
02464       snprintf(prompt,XrdSutMAXPPT, "Enter new password: ");
02465    } else if (ctype == kpCT_crypt) {
02466       String host(hs->Tag,hs->Tag.find("@",0)+1,hs->Tag.find(":",0)-1);
02467       snprintf(prompt,XrdSutMAXPPT, "Password for %s@%s: ", 
02468                                     hs->User.c_str(), host.c_str());
02469    } else if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
02470       snprintf(prompt,XrdSutMAXPPT, "AFS password for %s@%s: ", 
02471                                     hs->User.c_str(), hs->AFScell.c_str());
02472    } else {
02473       // Normal prompt
02474       snprintf(prompt,XrdSutMAXPPT,"Password for %s:",hs->Tag.c_str());
02475    }
02476    //
02477    // Inquire password
02478    int natt = MaxPrompts;
02479    String passwd = "";
02480    bool changepwd =0;
02481    while (natt-- && passwd.length() <= 0) {
02482       XrdSutGetPass(prompt, passwd);
02483       // If in the format $changepwd$<passwd> we are asking for
02484       // a password change
02485       if (passwd.beginswith("$changepwd$")) {
02486          PRINT("Requesting a password change");
02487          changepwd = 1;
02488          passwd.erase("$changepwd$",0,strlen("$changepwd$"));
02489       }
02490       if (passwd.length()) {
02491          // Fill in password
02492          creds->SetBuf(passwd.c_str(),passwd.length());
02493          if (ctype != kpCT_crypt && ctype != kpCT_afs) {
02494             // Self-Hash
02495             DoubleHash(hs->CF,creds,creds);
02496             // Update status
02497             status = kpCI_prompt;
02498          } else if (ctype == kpCT_afs) {
02499 #ifdef R__AFS
02500             // We will send over and encrypted version
02501             struct ktc_encryptionKey key;
02502             ka_StringToKey((char *) passwd.c_str(),
02503                            (char *) afsInfo.c_str(), &key);
02504             creds->SetBuf(key.data,8);
02505             // Tell the server
02506             afsInfo = "c";
02507             if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
02508                PRINT("Warning: problems updating bucket with AFS info");
02509 #endif
02510          }
02511          // Save creds to update auto-login file later
02512          // It will be flushed to file if required
02513          if (changepwd)
02514             hs->Pent->status = kPFE_onetime;
02515          else
02516             hs->Pent->status = kPFE_ok;
02517          hs->Pent->buf1.SetBuf(creds->buffer,creds->size);
02518          //
02519          // Just in case we need the passwd itself (like in crypt)
02520          hs->Pent->buf2.SetBuf(passwd.c_str(),passwd.length());
02521          // Update autologin, if required
02522          if (AutoLogin > 0)
02523             UpdateAlog();
02524       }
02525    }
02526    // Cleanup, if we did not get anything
02527    if (passwd.length() <= 0) {
02528       delete creds;
02529       creds = 0;
02530    }
02531    // We are done
02532    return creds;
02533 }
02534 
02535 //____________________________________________________________________
02536 int XrdSecProtocolpwd::UpdateAlog()
02537 {
02538    // Save pass hash in autologin file
02539    // Returns 0 if ok, -1 otherwise
02540    EPNAME("UpdateAlog");
02541 
02542    // Check inputs
02543    if (hs->Tag.length() <= 0) {
02544       DEBUG("Tag undefined - do nothing");
02545       return -1;
02546    }
02547    // Check inputs
02548    if (!(hs->Pent) || !(hs->Pent->buf1.buf)) {
02549       DEBUG("Nothing to do");
02550       return 0;
02551    }
02552    //
02553    // Build effective tag
02554    String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
02555    //
02556    // Make sure the other buffers are reset
02557    hs->Pent->buf2.SetBuf();
02558    hs->Pent->buf3.SetBuf();
02559    hs->Pent->buf4.SetBuf();
02560    //
02561    // Set entry status OK
02562    hs->Pent->status = kPFE_ok;
02563    //
02564    // Reset count
02565    hs->Pent->cnt = 0;
02566    //
02567    // Save entry
02568    hs->Pent->mtime = hs->TimeStamp;
02569    //
02570    DEBUG("Entry for tag: "<<wTag<<" updated in cache");
02571    //
02572    // Flush cache content to source file
02573    if (cacheAlog.Flush() != 0) {
02574       DEBUG("WARNING: some problem flushing to alog file after updating "<<wTag);
02575    }
02576    //
02577    // We are done
02578    return 0;
02579 }
02580 
02581 //____________________________________________________________________
02582 int XrdSecProtocolpwd::QueryUser(int &status, String &cmsg)
02583 {
02584    // Check that info about the defined user is available
02585    EPNAME("QueryUser");
02586 
02587    DEBUG("Enter: " << hs->User);
02588 
02589    // Check inputs
02590    if (hs->User.length() <= 0 || !hs->CF || !hs->Cref) {
02591       DEBUG("Invalid inputs ("<<hs->User.length()<<","<<hs->CF<<","<<hs->Cref<<")");
02592       return -1;
02593    }
02594    //
02595    // Build effective tag
02596    String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
02597    //
02598    // Default status
02599    status = kPFE_disabled;
02600    int bad = -1;
02601    cmsg = "";
02602    //
02603    // Check first info in user's home, if allowed
02604    if (UserPwd) {
02605       // Get userinfo
02606       struct passwd *pw = getpwnam(hs->User.c_str());
02607       int rcst = 0;
02608       kXR_int32 mtime = -1;
02609       bool fcrypt = 0;
02610       String File;
02611       if (pw) {
02612          File.resize(strlen(pw->pw_dir)+FileUser.length()+10);
02613          File.assign(pw->pw_dir, 0);
02614          File += FileUser;
02615          // Get status
02616          struct stat st;
02617          if ((rcst = stat(File.c_str(),&st)) != 0 && errno == ENOENT) {
02618             if (UserPwd > 1) {
02619                // Try special crypt like file
02620                File.replace(FileUser,FileCrypt);
02621                fcrypt = 1;
02622                rcst = 0;
02623             }
02624          }
02625          mtime = (rcst == 0) ? st.st_mtime : mtime;
02626       }
02627 
02628       if (rcst == 0) {
02629          //
02630          // Check cache first
02631          hs->Pent = cacheUser.Get(wTag.c_str());
02632          if (!hs->Pent || (hs->Pent->mtime < mtime)) {
02633             hs->Pent = (hs->Pent) ? hs->Pent : cacheUser.Add(wTag.c_str());
02634             if (hs->Pent) {
02635                //
02636                // Try the files
02637                if (!fcrypt) {
02638                   // Try to attach to File
02639                   XrdSutPFile ff(File.c_str(), kPFEopen,0,0);
02640                   if (ff.IsValid()) {
02641                      // Retrieve pwd information
02642                      if (ff.ReadEntry(wTag.c_str(),*(hs->Pent)) > 0) {
02643                         bad = 0;
02644                         status = hs->Pent->status;
02645                         ff.Close();
02646                         return 0;
02647                      }
02648                      ff.Close();
02649                   }
02650                } else if (UserPwd > 1) {
02651                   String pwhash;
02652                   if (QueryCrypt(FileCrypt, pwhash) > 0) {
02653                      bad = 0;
02654                      status = kPFE_crypt;
02655                      // Fill entry
02656                      hs->Pent->mtime = hs->TimeStamp;
02657                      hs->Pent->status = status;
02658                      hs->Pent->cnt = 0;
02659                      if (!FileCrypt.beginswith("afs:"))
02660                         hs->Pent->buf1.SetBuf(pwhash.c_str(),pwhash.length()+1);
02661                      // Trasmit the type of credentials we have found
02662                      cmsg = FileCrypt;
02663                      return 0;
02664                   }
02665                }
02666             }
02667          } else {
02668             // Fill entry
02669             bad = 0;
02670             status = hs->Pent->status;
02671             hs->Pent->mtime = hs->TimeStamp;
02672             if (status == kPFE_crypt)
02673                cmsg = FileCrypt;
02674             return 0;
02675          }
02676       }
02677    }
02678 
02679    //
02680    // Check system info, if enabled
02681    if (SysPwd) {
02682       String pwhash, fn;
02683       if (QueryCrypt(fn, pwhash) > 0) {
02684          bad = 0;
02685          status = kPFE_crypt;
02686          // Fill entry
02687          hs->Pent = cacheUser.Add(wTag.c_str());
02688          hs->Pent->mtime = hs->TimeStamp;
02689          hs->Pent->status = status;
02690          hs->Pent->cnt = 0;
02691          if (!fn.beginswith("afs:"))
02692             hs->Pent->buf1.SetBuf(pwhash.c_str(),pwhash.length()+1);
02693          // Trasmit the type of credentials we have found
02694          cmsg = fn;
02695          return 0;
02696       }
02697    }
02698    //
02699    // Check server admin files
02700    if (PFAdmin.IsValid()) {
02701       //
02702       // Make sure it is uptodate
02703       XrdSysPrivGuard priv(getuid(), getgid());
02704       if (priv.Valid()) {
02705          if (cacheAdmin.Refresh() != 0) {
02706             DEBUG("problems assuring cache update for file admin ");
02707             return -1;
02708          }
02709       }
02710       hs->Pent = cacheAdmin.Get(wTag.c_str());
02711       // Retrieve pwd information
02712       if (hs->Pent) {
02713          bad = 0;
02714          status = hs->Pent->status;
02715          if (status == kPFE_allowed) {
02716             if (AutoReg == kpAR_none) {
02717                // No auto-registration: disable
02718                status = kPFE_disabled;
02719                bad = 1;
02720             }
02721          } else if (status >= kPFE_ok) {
02722             // Check failure counter, if required
02723             if (MaxFailures > 0 && hs->Pent->cnt >= MaxFailures) {
02724                status = kPFE_disabled;
02725                bad = 2;
02726             }
02727             // Check expiration time, if required
02728             if (LifeCreds > 0) {
02729                int expt = hs->Pent->mtime + LifeCreds;
02730                int now = hs->TimeStamp;
02731                if (expt < now)
02732                   status = kPFE_expired;
02733             }
02734             if (status != kPFE_disabled)
02735                return 0;
02736          }
02737       }
02738    }
02739 
02740    //
02741    // If nothing found, auto-registration is enabled, and the tag 
02742    // corresponds to a local user, propose auto-registration
02743    if (bad == -1) {
02744       if (AutoReg != kpAR_none) {
02745          status = kPFE_allowed;
02746          if (AutoReg == kpAR_users) {
02747             struct passwd *pw = getpwnam(hs->User.c_str());
02748             if (!pw) {
02749                status = kPFE_disabled;
02750                bad = 1;
02751             }
02752          }
02753       } else
02754          bad = 1;
02755    }
02756    //
02757    // If disabled, fill salt string with message for the client
02758    if (status == kPFE_disabled) {
02759       char msg[XrdSutMAXPPT];
02760       switch (bad) {
02761       case 1:
02762          snprintf(msg,XrdSutMAXPPT,"user '%s' unknown: auto-registration"
02763                   " not allowed: contact %s to register",
02764                   hs->User.c_str(),SrvEmail.c_str());
02765          break;
02766       case 2:
02767          snprintf(msg,XrdSutMAXPPT,"max number of failures (%d) reached"
02768                   " for user '%s': contact %s to re-activate",
02769                   MaxFailures,hs->User.c_str(),SrvEmail.c_str());
02770          break;
02771       default:
02772          msg[0] = '\0';
02773       }
02774       cmsg.insert(msg,0,strlen(msg));
02775    }
02776    //
02777    // We are done
02778    return 0;
02779 }
02780 
02781 //_________________________________________________________________________
02782 int XrdSecProtocolpwd::GetUserHost(String &user, String &host)
02783 {
02784    // Resolve user and host
02785    EPNAME("GetUserHost");
02786 
02787    // Host
02788    host = Entity.host;
02789    if (host.length() <= 0) host = getenv("XrdSecHOST");
02790 
02791    // User
02792    user = Entity.name;
02793    if (user.length() <= 0) user = getenv("XrdSecUSER");
02794 
02795    // If user not given, prompt for it
02796    if (user.length() <= 0) {
02797       //
02798       // Make sure somebody can be prompted
02799       if (!(hs->Tty)) {
02800          DEBUG("user not defined:"
02801                "not tty: cannot prompt for user");
02802          return -1;
02803       }
02804       //
02805       // This is what we want
02806       String prompt = "Enter user or tag";
02807       if (host.length()) {
02808          prompt.append(" for host ");
02809          prompt.append(host);
02810       }
02811       prompt.append(":");
02812       XrdSutGetLine(user,prompt.c_str());
02813    }
02814 
02815    DEBUG(" user: "<<user<<", host: "<<host);
02816 
02817    // We are done
02818    return 0;
02819 }
02820 
02821 //_________________________________________________________________________
02822 int XrdSecProtocolpwd::AddSerialized(char opt, kXR_int32 step, String ID,
02823                                      XrdSutBuffer *bls, XrdSutBuffer *buf,
02824                                      kXR_int32 type,
02825                                      XrdCryptoCipher *cip)
02826 {
02827    // Serialize buf, and add it encrypted to bls as bucket type
02828    // Cipher cip is used if defined; else PuK rsa .
02829    // If both are undefined the buffer is just serialized and added.
02830    EPNAME("AddSerialized");
02831 
02832    if (!bls || !buf || (opt != 0 && opt != 'c' && opt != 's')) {
02833       DEBUG("invalid inputs ("
02834             <<bls<<","<<buf<<","<<opt<<")"
02835             <<" - type: "<<XrdSutBuckStr(type));
02836       return -1;
02837    }
02838 
02839    //
02840    // Add step to indicate the counterpart what we send
02841    if (step > 0) {
02842       bls->SetStep(step);
02843       buf->SetStep(step);
02844       hs->LastStep = step;
02845    }
02846 
02847    //
02848    // If a random tag has been sent and we have a session cipher,
02849    // we sign it
02850    XrdSutBucket *brt = buf->GetBucket(kXRS_rtag);
02851    if (brt && cip) {
02852       //
02853       // Encrypt random tag with session cipher
02854       if (cip->Encrypt(*brt) == 0) {
02855          DEBUG("error encrypting random tag");
02856          return -1;
02857       }
02858       //
02859       // Update type
02860       brt->type = kXRS_signed_rtag;
02861    }
02862    // Clients send in any case something session dependent: the server
02863    // may optionally decide that's enough and save one exchange.
02864    if (opt == 'c') {
02865       //
02866       // Add bucket with our timestamp to the main list
02867       if (buf->MarshalBucket(kXRS_timestamp,(kXR_int32)(hs->TimeStamp)) != 0) {
02868          DEBUG("error adding bucket with time stamp");
02869          return -1;
02870       }
02871    }
02872    //
02873    // Add an random challenge: if a next exchange is required this will
02874    // allow to prove authenticity of counter part
02875    if (opt == 's' || step != kXPC_autoreg) {
02876       //
02877       // Generate new random tag and create/update bucket
02878       String RndmTag;
02879       XrdSutRndm::GetRndmTag(RndmTag);
02880       //
02881       // Get bucket
02882       if (!(brt = new XrdSutBucket(RndmTag,kXRS_rtag))) {
02883          DEBUG("error creating random tag bucket");
02884          return -1;
02885       }
02886       buf->AddBucket(brt);
02887       //
02888       // Get cache entry
02889       if (!hs->Cref) {
02890          DEBUG("cache entry not found: protocol error");
02891          return -1;
02892       }
02893       //
02894       // Add random tag to the cache and update timestamp
02895       hs->Cref->buf1.SetBuf(brt->buffer,brt->size);      
02896       hs->Cref->mtime = (kXR_int32)hs->TimeStamp;
02897    }
02898    //
02899    // Now serialize the buffer ...
02900    char *bser = 0;
02901    int nser = buf->Serialized(&bser);
02902    //
02903    // Update bucket with this content
02904    XrdSutBucket *bck = 0;;
02905    if (!(bck = bls->GetBucket(type))) {
02906       // or create new bucket, if not existing
02907       if (!(bck = new XrdSutBucket(bser,nser,type))) {
02908          DEBUG("error creating bucket "
02909                <<" - type: "<<XrdSutBuckStr(type));
02910          return -1;
02911       }
02912       //
02913       // Add the bucket to the list
02914       bls->AddBucket(bck);      
02915    } else {
02916       bck->Update(bser,nser);
02917    }
02918    //
02919    // Encrypted the bucket
02920    if (cip) {
02921       if (cip->Encrypt(*bck) == 0) {
02922          DEBUG("error encrypting bucket - cipher "
02923                <<" - type: "<<XrdSutBuckStr(type));
02924          return -1;
02925       }
02926    }
02927    // We are done
02928    return 0;
02929 }
02930 
02931 //_________________________________________________________________________
02932 int XrdSecProtocolpwd::ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm,
02933                                         String &emsg)
02934 {
02935    // Parse received buffer b, extracting and decrypting the main 
02936    // buffer *bm and extracting the session 
02937    // cipher and server public keys, if there
02938    // Result used to fill the handshake local variables
02939    EPNAME("ParseClientInput");
02940 
02941    // Space for pointer to main buffer must be already allocated
02942    if (!br || !bm) {
02943       DEBUG("invalid inputs ("<<br<<","<<bm<<")");
02944       emsg = "invalid inputs";
02945       return -1;
02946    }
02947    //
02948    // Get the step
02949    XrdSutBucket *bckm = 0;
02950 
02951    // If first call, not much to do
02952    if (!br->GetNBuckets()) {
02953       // Create the main buffer as a copy of the buffer received
02954       if (!((*bm) = new XrdSutBuffer(br->GetProtocol(),br->GetOptions()))) {
02955          emsg = "error instantiating main buffer";
02956          return -1;
02957       }
02958       //
02959       // Extract server version from options
02960       String opts = br->GetOptions();
02961       int ii = opts.find("v:");
02962       if (ii >= 0) {
02963          String sver(opts,ii+2);
02964          sver.erase(sver.find(','));
02965          hs->RemVers = atoi(sver.c_str());
02966       } else {
02967          hs->RemVers = Version;
02968          emsg = "server version information not found in options:"
02969                 " assume same as local";
02970       }
02971       //
02972       // Create cache
02973       if (!(hs->Cref = new XrdSutPFEntry("c"))) {
02974          emsg = "error creating cache";
02975          return -1;
02976       }
02977       //
02978       // Save server version in cache
02979       hs->Cref->status = hs->RemVers;
02980       //
02981       // Extract server ID
02982       String srvid;
02983       ii = opts.find("id:");
02984       if (ii >= 0) {
02985          srvid.assign(opts, ii+3);
02986          srvid.erase(srvid.find(','));
02987       }
02988       //
02989       // Extract priority options
02990       String popt;
02991       ii = opts.find("po:");
02992       if (ii >= 0) {
02993          popt.assign(opts, ii+3);
02994          popt.erase(popt.find(','));
02995          // Parse it
02996          if (popt.beginswith("sys")) {
02997             hs->SysPwd = 1;
02998          } else if (popt.beginswith("afs")) {
02999             hs->SysPwd = 2;
03000             hs->AFScell.assign(popt,3);
03001          }
03002       }
03003       //
03004       // Get user and host
03005       String host;
03006       if (GetUserHost(hs->User,host) != 0) {
03007          emsg = "error getting user and host";
03008          return -1;
03009       }
03010       //
03011       // Build tag and save it into the cache
03012       hs->Tag.resize(hs->User.length()+host.length()+srvid.length()+5);
03013       hs->Tag = hs->User;
03014       if (host.length() > 0)
03015          hs->Tag += ("@" + host);
03016       if (srvid.length() > 0)
03017          hs->Tag += (":" + srvid);
03018       //
03019       // Get server puk from cache and initialize handshake cipher
03020       if (!PFSrvPuk.IsValid()) {
03021          emsg = "file with server public keys invalid";
03022          return -1;
03023       }
03024       char *ptag = new char[host.length()+srvid.length()+10];
03025       if (ptag) {
03026          sprintf(ptag,"%s:%s_%d",host.c_str(),srvid.c_str(),hs->CF->ID());
03027          bool wild = 0;
03028          XrdSutPFEntry *ent = cacheSrvPuk.Get((const char *)ptag, &wild);
03029          if (ent) {
03030             // Initialize cipher
03031             SafeDelete(hs->Hcip);
03032             if (!(hs->Hcip =
03033                   hs->CF->Cipher(0,ent->buf1.buf,ent->buf1.len))) {
03034                      DEBUG("could not instantiate session cipher "
03035                            "using cipher public info from server");
03036                      emsg = "could not instantiate session cipher ";
03037             } else {
03038                DEBUG("hsHcip: 0x"<<hs->Hcip->AsHexString());
03039             }
03040          } else {
03041             // Autoreg is the only alternative at this point ...
03042             emsg = "server puk not found in cache - tag: ";
03043             emsg += ptag;
03044          }
03045          SafeDelArray(ptag);
03046       } else 
03047          emsg = "could not allocate buffer for server puk tag";
03048       //
03049       // And we are done;
03050       return 0;
03051    }
03052    //
03053    // make sure the cache is still there
03054    if (!hs->Cref) {
03055       emsg = "cache entry not found";
03056       return -1;
03057    }
03058    //
03059    // make sure is not too old
03060    int reftime = hs->TimeStamp - TimeSkew;
03061    if (hs->Cref->mtime < reftime) {
03062       emsg = "cache entry expired";
03063       // Remove: should not be checked a second time
03064       SafeDelete(hs->Cref);
03065       return -1;
03066    }
03067    //
03068    // Get from cache version run by server
03069    hs->RemVers = hs->Cref->status;
03070    //
03071    // Extract the main buffer 
03072    if (!(bckm = br->GetBucket(kXRS_main))) {
03073       emsg = "main buffer missing";
03074       return -1;
03075    }
03076    //
03077    // Decrypt, if it makes sense
03078    if (hs->LastStep != kXPC_autoreg) {
03079       //
03080       // make sure the cache is still there
03081       if (!hs->Hcip) {
03082          emsg = "session cipher not found";
03083          return -1;
03084       }
03085       //
03086       // Decrypt it 
03087       if (!(hs->Hcip->Decrypt(*bckm))) {
03088          emsg = "error decrypting main buffer with session cipher";
03089          return -1;
03090       }
03091    }
03092    //
03093    // Deserialize main buffer
03094    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
03095       emsg = "error deserializing main buffer";
03096       return -1;
03097    }
03098    //
03099    // If (new) server public keys are there extract and save them
03100    bool newpuk = 0;
03101    XrdSutBuckList *bcklst = (*bm)->GetBuckList();
03102    XrdSutBucket *bp = bcklst->Begin();
03103    while (bp) {
03104       if (bp->type == kXRS_puk) {
03105          newpuk = 1;
03106          // ID is in the first 4 chars ( ....'\0'<puk>)
03107          char cid[5] = {0};
03108          memcpy(cid, bp->buffer, 5);
03109          int id = atoi(cid);
03110          // Build tag
03111          String ptag(hs->Tag);
03112          ptag.erase(0,ptag.find('@')+1);
03113          ptag += '_';
03114          ptag += cid;
03115          // Update or create new entry
03116          XrdSutPFEntry *ent = cacheSrvPuk.Add(ptag.c_str());
03117          if (ent) {
03118             // Set buffer
03119             ent->buf1.SetBuf((bp->buffer)+5,(bp->size)-5);
03120             ent->mtime = hs->TimeStamp;
03121             if (id == hs->CF->ID()) {
03122                // Initialize cipher
03123                SafeDelete(hs->Hcip);
03124                if (!(hs->Hcip =
03125                      hs->CF->Cipher(0,ent->buf1.buf,ent->buf1.len))) {
03126                         DEBUG("could not instantiate session cipher "
03127                               "using cipher public info from server");
03128                         emsg = "could not instantiate session cipher ";
03129                } else {
03130                   DEBUG("hsHcip: 0x"<<hs->Hcip->AsHexString());
03131                }
03132             }
03133         } else {
03134             // Autoreg is the only alternative at this point ...
03135             DEBUG("could not create entry in cache - tag: "<<ptag);
03136          }
03137       }
03138       // Get next
03139       bp = bcklst->Next();
03140    }
03141    (*bm)->Deactivate(kXRS_puk);   
03142    // Update the puk file (for the other sessions ...)
03143    if (newpuk)
03144       cacheSrvPuk.Flush();
03145    //
03146    // We are done
03147    return 0;
03148 }
03149 
03150 //_________________________________________________________________________
03151 int XrdSecProtocolpwd::ParseServerInput(XrdSutBuffer *br, XrdSutBuffer **bm,
03152                                         String &cmsg)
03153 {
03154    // Parse received buffer b, extracting and decrypting the main 
03155    // buffer *bm and extracting the session 
03156    // cipher, random tag buckets and user name, if any.
03157    // Results used to fill the local handshake variables
03158    EPNAME("ParseServerInput");
03159 
03160    // Space for pointer to main buffer must be already allocated
03161    if (!br || !bm) {
03162       DEBUG("invalid inputs ("<<br<<","<<bm<<")");
03163       cmsg = "invalid inputs";
03164       return -1;
03165    }
03166    //
03167    // Get the step
03168    XrdSutBucket *bck = 0;
03169    XrdSutBucket *bckm = 0;
03170    //
03171    // Extract the main buffer 
03172    if (!(bckm = br->GetBucket(kXRS_main))) {
03173       cmsg = "main buffer missing";
03174       return -1;
03175    }
03176    //
03177    // First get the session cipher
03178    if ((bck = br->GetBucket(kXRS_puk))) {
03179       //
03180       // Cleanup
03181       SafeDelete(hs->Hcip);
03182       //
03183       // Prepare cipher agreement: make sure we have the reference cipher
03184       if (!hs->Rcip) {
03185          cmsg = "reference cipher missing";
03186          return -1;
03187       }
03188       // Prepare cipher agreement: get a copy of the reference cipher
03189       if (!(hs->Hcip = hs->CF->Cipher(*hs->Rcip))) {
03190          cmsg = "cannot get reference cipher";
03191          return -1;
03192       }
03193       //
03194       // Instantiate the session cipher 
03195       if (!(hs->Hcip->Finalize(bck->buffer,bck->size,0))) {
03196          cmsg = "cannot finalize session cipher";
03197          return -1;
03198       }
03199       //
03200       // We need it only once
03201       br->Deactivate(kXRS_puk);
03202    }
03203 
03204    //
03205    // Decrypt the main buffer with the session cipher, if available
03206    if (hs->Hcip) {
03207       if (!(hs->Hcip->Decrypt(*bckm))) {
03208          cmsg = "error decrypting main buffer with session cipher";
03209          return -1;
03210       }
03211    }
03212    //
03213    // Deserialize main buffer
03214    if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
03215       cmsg = "error deserializing main buffer";
03216       return -1;
03217    }
03218    //
03219    // Get version run by client, if there
03220    if (hs->RemVers == -1) {
03221       if ((*bm)->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
03222          hs->RemVers = Version;
03223          cmsg = "client version information not found in options:"
03224                 " assume same as local";
03225       } else {
03226         (*bm)->Deactivate(kXRS_version);
03227       }
03228    }
03229 
03230    //
03231    // Get cache entry or create a new one
03232    if (!hs->Cref) {
03233       // Create it
03234       if (!(hs->Cref = new XrdSutPFEntry(hs->ID.c_str()))) {
03235          cmsg = "cannot create cache entry";
03236          return -1;
03237       }
03238    } else {
03239       //
03240       // make sure cache is not too old
03241       int reftime = hs->TimeStamp - TimeSkew;
03242       if (hs->Cref->mtime < reftime) {
03243          cmsg = "cache entry expired";
03244          SafeDelete(hs->Cref);
03245          return -1;
03246       }
03247    }
03248 
03249    //
03250    // Extract user name, if any
03251    if ((bck = (*bm)->GetBucket(kXRS_user))) {
03252       if (hs->User.length() <= 0) {
03253          bck->ToString(hs->User);
03254          // Build tag
03255          hs->Tag = hs->User;
03256       }
03257       (*bm)->Deactivate(kXRS_user);
03258    }
03259    //
03260    // We are done
03261    return 0;
03262 }
03263 
03264 //__________________________________________________________________
03265 void XrdSecProtocolpwd::ErrF(XrdOucErrInfo *einfo, kXR_int32 ecode,
03266                              const char *msg1, const char *msg2,
03267                              const char *msg3)
03268 {
03269    // Filling the error structure
03270    EPNAME("ErrF");
03271 
03272    char *msgv[12];
03273    int k, i = 0, sz = strlen("Secpwd");
03274 
03275    //
03276    // Code message, if any
03277    int cm = (ecode >= kPWErrParseBuffer && 
03278              ecode <= kPWErrError) ? (ecode-kPWErrParseBuffer) : -1;
03279    const char *cmsg = (cm > -1) ? gPWErrStr[cm] : 0;
03280 
03281    //
03282    // Build error message array
03283               msgv[i++] = (char *)"Secpwd";     //0
03284    if (cmsg) {msgv[i++] = (char *)": ";         //1
03285               msgv[i++] = (char *)cmsg;         //2
03286               sz += strlen(msgv[i-1]) + 2;
03287              }
03288    if (msg1) {msgv[i++] = (char *)": ";         //3
03289               msgv[i++] = (char *)msg1;         //4
03290               sz += strlen(msgv[i-1]) + 2;
03291              }
03292    if (msg2) {msgv[i++] = (char *)": ";         //5
03293               msgv[i++] = (char *)msg2;         //6
03294               sz += strlen(msgv[i-1]) + 2;
03295              }
03296    if (msg3) {msgv[i++] = (char *)": ";         //7
03297               msgv[i++] = (char *)msg3;         //8
03298               sz += strlen(msgv[i-1]) + 2;
03299              }
03300 
03301    // save it (or print it)
03302    if (einfo) {
03303       einfo->setErrInfo(ecode, (const char **)msgv, i);
03304    }
03305    if (QTRACE(Debug)) {
03306       char *bout = new char[sz+10];
03307       if (bout) {
03308          bout[0] = 0;
03309          for (k = 0; k < i; k++)
03310             sprintf(bout,"%s%s",bout,msgv[k]);
03311          DEBUG(bout);
03312       } else {
03313          for (k = 0; k < i; k++)
03314             DEBUG(msgv[k]);
03315       }
03316    }
03317 }
03318 
03319 //__________________________________________________________________
03320 XrdSecCredentials *XrdSecProtocolpwd::ErrC(XrdOucErrInfo *einfo,
03321                                            XrdSutBuffer *b1,
03322                                            XrdSutBuffer *b2,
03323                                            XrdSutBuffer *b3,
03324                                            kXR_int32 ecode,
03325                                            const char *msg1,
03326                                            const char *msg2,
03327                                            const char *msg3)
03328 {
03329    // Error logging client method
03330 
03331    // Fill the error structure
03332    ErrF(einfo, ecode, msg1, msg2, msg3);
03333 
03334    // Release buffers
03335    REL3(b1,b2,b3);
03336 
03337    // We are done
03338    return (XrdSecCredentials *)0;
03339 }
03340 
03341 //__________________________________________________________________
03342 int XrdSecProtocolpwd::ErrS(String ID, XrdOucErrInfo *einfo,
03343                             XrdSutBuffer *b1, XrdSutBuffer *b2,
03344                             XrdSutBuffer *b3, kXR_int32 ecode,
03345                             const char *msg1, const char *msg2,
03346                             const char *msg3)
03347 {
03348    // Error logging server method
03349 
03350    // Fill the error structure
03351    ErrF(einfo, ecode, msg1, msg2, msg3);
03352 
03353    // Release buffers
03354    REL3(b1,b2,b3);
03355 
03356    // We are done
03357    return kpST_error;
03358 }
03359 
03360 //_______________________________________________________________________
03361 int XrdSecProtocolpwd::DoubleHash(XrdCryptoFactory *cf, XrdSutBucket *bck,
03362                                   XrdSutBucket *s1, XrdSutBucket *s2,
03363                                   const char *tag)
03364 {
03365    // Apply single or double hash to bck using salts
03366    // in s1 and (if defined) s2.
03367    // Store result in *buf, with the new length in len.
03368    // Return 0 if ok or -1 otherwise
03369    EPNAME("DoubleHash");
03370 
03371    //
03372    // Check inputs
03373    if (!cf || !bck) {
03374       DEBUG("Bad inputs "<<cf<<","<<bck<<")");
03375       return -1;
03376    }
03377    //
03378    // At least one salt must be defined
03379    if ((!s1 || s1->size <= 0) && (!s2 || s2->size <= 0)) {
03380       DEBUG("Both salts undefined - do nothing");
03381       return 0;
03382    }
03383    //
03384    // Tag length, if there
03385    int ltag = (tag) ? strlen(tag) + 1 : 0;
03386    //
03387    // Get one-way hash function
03388    XrdCryptoKDFun_t KDFun = cf->KDFun();
03389    XrdCryptoKDFunLen_t KDFunLen = cf->KDFunLen();
03390    if (!KDFun || !KDFunLen) {
03391       DEBUG("Could not get hooks to one-way hash functions ("
03392             <<KDFun<<","<<KDFunLen<<")");
03393       return -1;
03394    }
03395    //
03396    // Apply first salt, if defined
03397    char *nhash = 0, *thash = bck->buffer;
03398    int nhlen = bck->size;
03399    if (s1 && s1->size > 0) {
03400       if (!(nhash = new char[(*KDFunLen)() + ltag])) {
03401          DEBUG("Could not allocate memory for hash - s1");
03402          return -1;
03403       }
03404       if ((nhlen = (*KDFun)(thash,nhlen,
03405                             s1->buffer,s1->size,nhash+ltag,0)) <= 0) {
03406          DEBUG("Problems hashing - s1");
03407          delete[] nhash;
03408          return -1;
03409       }
03410       thash = nhash;
03411    }
03412    //
03413    // Apply second salt, if defined
03414    if (s2 && s2->size > 0) {
03415       if (!(nhash = new char[(*KDFunLen)() + ltag])) {
03416          DEBUG("Could not allocate memory for hash - s2");
03417          return -1;
03418       }
03419       if (thash && thash != bck->buffer) thash += ltag;
03420       if ((nhlen = (*KDFun)(thash,nhlen,
03421                             s2->buffer,s2->size,nhash+ltag,0)) <= 0) {
03422          DEBUG("Problems hashing - s2");
03423          delete[] nhash;
03424          if (thash && thash != bck->buffer) delete[] thash;
03425          return -1;
03426       }
03427       if (thash && thash != bck->buffer) delete[] thash;
03428       thash = nhash;
03429    }
03430    //
03431    // Add tag if there
03432    if (tag)
03433       memcpy(thash,tag,ltag);
03434    //
03435    // Save result
03436    bck->SetBuf(thash,nhlen+ltag);
03437    //
03438    // We are done
03439    return 0;
03440 }
03441 
03442 //______________________________________________________________________________
03443 int XrdSecProtocolpwd::QueryCrypt(String &fn, String &pwhash)
03444 {
03445    // Retrieve crypt-like password-hash from $HOME/fn or from system password files,
03446    // if accessible.
03447    // To avoid problems with NFS-root-squashing, if 'root' changes temporarly the
03448    // uid/gid to those of the target user (usr).   
03449    // If OK, returns pass length and fill 'pass' with the password, null-terminated.
03450    // ('pass' is allocated externally to contain max lpwmax bytes).
03451    // If the file does not exists, return 0 and an empty pass.
03452    // If any problems with the file occurs, return a negative
03453    // code, -2 indicating wrong file permissions.
03454    // If any problem with changing ugid's occurs, prints a warning trying anyhow
03455    // to read the password hash.
03456    EPNAME("QueryCrypt");
03457 
03458    int rc = -1;
03459    int len = 0, n = 0, fid = -1;
03460    pwhash = "";
03461    DEBUG("analyzing file: "<<fn);
03462 
03463    //
03464    // Get the password structure
03465    struct passwd *pw = getpwnam(hs->User.c_str());
03466    if (!pw) {
03467       DEBUG("Cannot get pwnam structure for user "<<hs->User);
03468       return -1;
03469    }
03470    //
03471    // Check the user specific file first, if requested
03472    if (fn.length() > 0) {
03473 
03474       // target uid
03475       int uid = pw->pw_uid;
03476 
03477       // Acquire the privileges, if needed
03478       XrdSysPrivGuard priv(uid, pw->pw_gid);
03479       bool go = priv.Valid();
03480       if (!go) {
03481          DEBUG("problems acquiring temporarly identity: "<<hs->User);
03482       }
03483 
03484       // The file
03485       String fpw(pw->pw_dir, strlen(pw->pw_dir) + fn.length() + 5);
03486       if (go) {
03487          fpw += ("/" + fn);
03488          DEBUG("checking file "<<fpw<<" for user "<<hs->User);
03489       }
03490 
03491       // Check first the permissions: should be 0600
03492       struct stat st;
03493       if (go && stat(fpw.c_str(), &st) == -1) {
03494          if (errno != ENOENT) {
03495             DEBUG("cannot stat password file "<<fpw<<" (errno:"<<errno<<")");
03496             rc = -1;
03497          } else {
03498             DEBUG("file "<<fpw<<" does not exist");
03499             rc = 0;
03500          }
03501          go = 0;
03502       }
03503       if (go &&
03504          (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
03505           (st.st_mode & (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH)) != 0)) {
03506          DEBUG("pass file "<<fpw<<": wrong permissions "<<
03507                (st.st_mode & 0777) << " (should be 0600)");
03508          rc = -2;
03509          go = 0;
03510       }
03511 
03512       // Open the file
03513       if (go && (fid = open(fpw.c_str(), O_RDONLY)) == -1) {
03514          DEBUG("cannot open file "<<fpw<<" (errno:"<<errno<<")");
03515          rc = -1;
03516          go = 0;
03517       }
03518 
03519       // Read password-hash
03520       char pass[128];
03521       if (go && (n = read(fid, pass, sizeof(pass)-1)) <= 0) {
03522          close(fid);
03523          DEBUG("cannot read file "<<fpw<<" (errno:"<<errno<<")");
03524          rc = -1;
03525          go = 0;
03526       }
03527       if (fid > -1)
03528          close(fid);
03529 
03530       // Get rid of special trailing chars 
03531       if (go) {
03532          len = n;
03533          while (len-- && (pass[len] == '\n' || pass[len] == 32))
03534             pass[len] = 0;
03535          // Null-terminate
03536          pass[++len] = 0;
03537          rc = len;
03538          // Prepare for output
03539          pwhash = pass;
03540       }
03541    }
03542    //
03543    // If we go a pw-hash we are done
03544    if (pwhash.length() > 0)
03545       return rc;
03546    //
03547    // If not, we check the system files
03548 #ifdef R__AFS
03549    // Send over the cell
03550    fn = "afs:";
03551    fn += ka_LocalCell();
03552    pwhash = "afs";
03553 #else
03554 #ifdef R__SHADOWPW
03555    {  // Acquire the privileges; needs to be 'superuser' to access the
03556       // shadow password file
03557       XrdSysPrivGuard priv((uid_t)0, (gid_t)0);
03558       if (priv.Valid()) {
03559          struct spwd *spw = 0;
03560          // System V Rel 4 style shadow passwords
03561          if ((spw = getspnam(hs->User.c_str())) == 0) {
03562             DEBUG("shadow passwd not accessible to this application");
03563          } else
03564             pwhash = spw->sp_pwdp;
03565       } else {
03566          DEBUG("problems acquiring temporarly superuser privileges");
03567       }
03568    }
03569 #else
03570    pwhash = pw->pw_passwd;
03571 #endif
03572    //
03573    // This is send back to the client to locate autologin info
03574    fn = "system";
03575 #endif
03576    // Check if successful
03577    if ((rc = pwhash.length()) <= 2) {
03578       DEBUG("passwd hash not available for user "<<hs->User);
03579       pwhash = "";
03580       fn = "";
03581       rc = -1;
03582    }
03583 
03584    // We are done
03585    return rc;
03586 }
03587 
03588 //______________________________________________________________________________
03589 int XrdSecProtocolpwd::QueryNetRc(String host, String &passwd, int &status)
03590 {
03591    // Check netrc-like file defined by env 'XrdSecNETRC' for password information
03592    // matching ('user','host') and return the password in 'passwd'.
03593    // If found, 'status' is filled with 'kpCI_exact' or 'kpCI_wildcard' 
03594    // depending the type of match.
03595    // Same syntax as $HOME/.netrc is required; wild cards for hosts are 
03596    // supported: examples
03597    //
03598    // machine oplapro027.cern.ch login qwerty password Rt8dsAvV0
03599    // machine lxplus*.cern.ch login poiuyt password WtHAyD0iG
03600    //
03601    // Returns 0 is something found, -1 otherwise.
03602    // NB: file permissions must be: readable/writable by the owner only 
03603    EPNAME("QueryNetRc");
03604    passwd = ""; 
03605    //
03606    // Make sure a file name is defined
03607    String fnrc = getenv("XrdSecNETRC");
03608    if (fnrc.length() <= 0) {
03609       DEBUG("File name undefined");
03610       return -1;
03611    }
03612    // Resolve place-holders, if any
03613    if (XrdSutResolve(fnrc, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
03614       DEBUG("Problems resolving templates in "<<fnrc);
03615       return -1;
03616    }
03617    DEBUG("checking file "<<fnrc<<" for user "<<hs->User);
03618 
03619    // Check first the permissions: should be 0600
03620    struct stat st;
03621    if (stat(fnrc.c_str(), &st) == -1) {
03622       if (errno != ENOENT) {
03623          DEBUG("cannot stat password file "<<fnrc<<" (errno:"<<errno<<")");
03624       } else {
03625          DEBUG("file "<<fnrc<<" does not exist");
03626       }
03627       return -1;
03628    }
03629    if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
03630        (st.st_mode & (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH)) != 0) {
03631       DEBUG("pass file "<<fnrc<<": wrong permissions "<<
03632             (st.st_mode & 0777) << " (should be 0600)");
03633       return -2;
03634    }
03635    // Open the file
03636    FILE *fid = fopen(fnrc.c_str(), "r");
03637    if (!fid) {
03638       DEBUG("cannot open file "<<fnrc<<" (errno:"<<errno<<")");
03639       return -1;
03640    }
03641    char line[512];
03642    int nm = 0, nmmx = -1;
03643    while (fgets(line, sizeof(line), fid) != 0) {
03644       if (line[0] == '#')
03645          continue;
03646       char word[6][128];
03647       int nword = sscanf(line, "%s %s %s %s %s %s", word[0], word[1],
03648                          word[2], word[3], word[4], word[5]);
03649       if (nword != 6) continue;
03650       if (strcmp(word[0], "machine") || strcmp(word[2], "login") ||
03651           strcmp(word[4], "password"))
03652          continue;
03653       // Good entry format
03654       if ((nm = host.matches(word[1])) > 0) {
03655          // Host matches
03656          if (!strcmp(hs->User.c_str(),word[3])) {
03657             // User matches: if exact match we are done
03658             if (nm == host.length()) {
03659                passwd = word[5];
03660                status = kpCI_exact;
03661                break;
03662             } 
03663             // Else, we focalise on the best match
03664             if (nm > nmmx) {
03665                nmmx = nm;
03666                passwd = word[5];
03667                status = kpCI_wildcard;
03668             }
03669          }
03670       }
03671    }
03672    //
03673    // Close the file
03674    fclose(fid);
03675    //
03676    // We are done
03677    if (passwd.length() > 0)
03678       return 0;
03679    return -1;
03680 }
03681 
03682 //______________________________________________________________________________
03683 bool XrdSecProtocolpwd::CheckTimeStamp(XrdSutBuffer *bm, int skew, String &emsg)
03684 {
03685    // Check consistency of the time stamp in bucket kXRS_timestamp in bm;
03686    // skew is the allowed difference in times.
03687    // Return 1 if ok, 0 if not
03688    EPNAME("CheckTimeStamp");
03689 
03690    // Check inputs
03691    if (!bm || skew <= 0) { 
03692       if (!bm)
03693          emsg = "input buffer undefined ";
03694       else
03695          emsg = "negative skew: invalid ";
03696       return 0;
03697    }
03698 
03699    // We check only if requested and a stronger check has not been done
03700    // successfully already
03701    if (hs->RtagOK || VeriClnt != 1) {
03702       DEBUG("Nothing to do");
03703       // Deactivate the buffer, if there
03704       if (bm->GetBucket(kXRS_timestamp))
03705           bm->Deactivate(kXRS_timestamp);
03706       return 1;
03707    }
03708 
03709    //
03710    // Add bucket with our version to the main list
03711    kXR_int32 tstamp = 0;
03712    if (bm->UnmarshalBucket(kXRS_timestamp,tstamp) != 0) {
03713       emsg = "bucket with time stamp not found";
03714       return 0;
03715    }
03716 
03717    kXR_int32 dtim = hs->TimeStamp - tstamp;
03718    dtim = (dtim < 0) ? -dtim : dtim;
03719    if (dtim > skew) {
03720       emsg = "time difference too big: "; emsg += (int)dtim;
03721       emsg += " - allowed skew: "; emsg += skew;
03722       bm->Deactivate(kXRS_timestamp);
03723       return 0;
03724    }
03725    bm->Deactivate(kXRS_timestamp);
03726 
03727    DEBUG("Time stamp successfully checked");
03728 
03729    // Ok
03730    return 1;
03731 }
03732 
03733 //______________________________________________________________________________
03734 bool XrdSecProtocolpwd::CheckRtag(XrdSutBuffer *bm, String &emsg)
03735 {
03736    // Check random tag signature if it was sent with previous packet
03737    EPNAME("CheckRtag");
03738 
03739    // Make sure we got a buffer
03740    if (!bm) {
03741       emsg = "Buffer not defined";
03742       return 0;
03743    }
03744    //
03745    // If we sent out a random tag check it signature
03746    if (hs->Cref && hs->Cref->buf1.len > 0) {
03747       XrdSutBucket *brt = 0;
03748       if ((brt = bm->GetBucket(kXRS_signed_rtag))) {
03749          // Make suer we got a cipher
03750          if (!(hs->Hcip)) {
03751             emsg = "Session cipher undefined";
03752             return 0;
03753          }
03754          // Decrypt it with the session cipher
03755          if (!(hs->Hcip->Decrypt(*brt))) {
03756             emsg = "error decrypting random tag with session cipher";
03757             return 0;
03758          }
03759       } else {
03760          emsg = "random tag missing - protocol error";
03761          return 0;
03762       } 
03763       //
03764       // Random tag cross-check: content
03765       if (memcmp(brt->buffer,hs->Cref->buf1.buf,hs->Cref->buf1.len)) {
03766          emsg = "random tag content mismatch";
03767          SafeDelete(hs->Cref);
03768          // Remove: should not be checked a second time
03769          return 0;
03770       }
03771       //
03772       // Reset the cache entry but we will not use the info a second time
03773       memset(hs->Cref->buf1.buf,0,hs->Cref->buf1.len);
03774       hs->Cref->buf1.SetBuf();
03775       //
03776       // Flag successful check
03777       hs->RtagOK = 1;
03778       bm->Deactivate(kXRS_signed_rtag);
03779       DEBUG("Random tag successfully checked");
03780    } else {
03781       DEBUG("Nothing to check");
03782    }
03783 
03784    // We are done
03785    return 1;
03786 }

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