XrdSecpwdSrvAdmin.cc

Go to the documentation of this file.
00001 // $Id: XrdSecpwdSrvAdmin.cc 30949 2009-11-02 16:37:58Z ganis $
00002 
00003 const char *XrdSecpwdSrvAdminCVSID = "$Id: XrdSecpwdSrvAdmin.cc 30949 2009-11-02 16:37:58Z ganis $";
00004 // ---------------------------------------------------------------------- //
00005 //                                                                        //
00006 //   Password file administration                                         //
00007 //                                                                        //
00008 //   Use this application to:                                             //
00009 //                                                                        //
00010 //      - Create / Modify a password file for servers under your          //
00011 //        administration.                                                 //
00012 //        Default location and name $(HOME)/.xrd/pwdadmin]                //
00013 //                                                                        //
00014 //          XrdSecpwdSrvAdmin [<file>]                                    //
00015 //                                                                        //
00016 //        NB: permissions must be such that the file is                   //
00017 //            readable and writable by owner only, e.g. 0600              //
00018 //                                                                        //
00019 //                                                                        //
00020 //      - Create / Modify a password file for servers enabled to verify   //
00021 //        user passwords [default location and name $(HOME)/.xrd/pwduser] //
00022 //                                                                        //
00023 //          XrdSecpwdSrvAdmin -m user [<file>]                            //
00024 //                                                                        //
00025 //        NB: copy the file on the server machine if you are producing    //
00026 //            it elsewhere; permissions must be such that the file is     //
00027 //            writable by owner only, e.g. 0644                           //
00028 //                                                                        //
00029 //                                                                        //
00030 //      - Create / Modify a autologin file                                //
00031 //        [default location and name $(HOME)/.xrd/pwdnetrc]               //
00032 //                                                                        //
00033 //          XrdSecpwdSrvAdmin -m netrc [<file>]                           //
00034 //                                                                        //
00035 //        NB: permissions must be such that the file is                   //
00036 //            readable and writable by owner only, e.g. 0600              //
00037 //                                                                        //
00038 //      - Create / Modify the file with server public cipher initiators   //
00039 //        [default location and name $(HOME)/.xrd/pwdsrvpuk]              //
00040 //                                                                        //
00041 //          XrdSecpwdSrvAdmin -m srvpuk [<file>]                          //
00042 //                                                                        //
00043 //        NB: permissions must be such that the file is                   //
00044 //            writable by owner only, e.g. 0644                           //
00045 //                                                                        //
00046 //                                                                        //
00047 //  Author: G.Ganis, 2005                                                 //
00048 // ---------------------------------------------------------------------- //
00049 #include <stdio.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 #include <sys/types.h>
00053 #include <sys/stat.h>
00054 #include <unistd.h>
00055 #include <sys/types.h>
00056 #include <fcntl.h>
00057 #include <errno.h>
00058 #include <pwd.h>
00059 #include <dirent.h>
00060 
00061 #include <XrdOuc/XrdOucString.hh>
00062 
00063 #include <XrdSut/XrdSutAux.hh>
00064 #include <XrdSut/XrdSutPFEntry.hh>
00065 #include <XrdSut/XrdSutPFile.hh>
00066 #include <XrdSut/XrdSutRndm.hh>
00067 
00068 #include <XrdCrypto/XrdCryptoCipher.hh>
00069 #include <XrdCrypto/XrdCryptoFactory.hh>
00070 
00071 //
00072 // enum
00073 enum kModes {
00074    kM_undef = 0,
00075    kM_admin = 1,
00076    kM_user,
00077    kM_netrc,
00078    kM_srvpuk,
00079    kM_help
00080 };
00081 const char *gModesStr[] = {
00082    "kM_undef",
00083    "kM_admin",
00084    "kM_user",
00085    "kM_netrc",
00086    "kM_srvpuk",
00087    "kM_help"
00088 };
00089 enum kActions {
00090    kA_undef = 0,
00091    kA_add   = 1,
00092    kA_update,
00093    kA_read,
00094    kA_remove,
00095    kA_disable,
00096    kA_copy,
00097    kA_trim,
00098    kA_browse
00099 };
00100 const char *gActionsStr[] = {
00101    "kA_undef",
00102    "kA_add",
00103    "kA_update",
00104    "kA_read",
00105    "kA_remove",
00106    "kA_disable",
00107    "kA_copy",
00108    "kA_trim",
00109    "kA_browse"
00110 };
00111 
00112 //
00113 // Globals 
00114 int DebugON = 1;
00115 XrdOucString DirRef   = "~/.xrd/";
00116 XrdOucString AdminRef = "pwdadmin";
00117 XrdOucString UserRef  = "pwduser";
00118 XrdOucString NetRcRef = "pwdnetrc";
00119 XrdOucString SrvPukRef= "pwdsrvpuk";
00120 XrdOucString GenPwdRef= "/genpwd/";
00121 XrdOucString GenPukRef= "/genpuk/";
00122 XrdOucString IDTag    = "+++SrvID";
00123 XrdOucString EmailTag = "+++SrvEmail";
00124 XrdOucString HostTag  = "+++SrvHost";
00125 XrdOucString PukTag   = "+++SrvPuk";
00126 XrdOucString PwdFile  = "";
00127 XrdOucString PukFile  = "/home/ganis/.xrd/genpuk/puk.07May2005-0849";
00128 int          Mode     = kM_undef;
00129 int          Action   = kA_undef;
00130 int          NoBackup = 1;
00131 XrdOucString NameTag  = "";
00132 XrdOucString CopyTag  = "";
00133 XrdOucString File     = "";
00134 XrdOucString Path     = "";
00135 XrdOucString Dir      = "";
00136 XrdOucString SrvID    = "";
00137 XrdOucString SrvName  = "";
00138 XrdOucString Email    = "";
00139 XrdOucString IterNum  = "";
00140 bool         Backup   = 1;
00141 bool         DontAsk  = 0;
00142 bool         Force    = 0;
00143 bool         Passwd   = 1;
00144 bool         Change   = 1;
00145 bool         Random   = 0;
00146 bool         SavePw   = 1;
00147 bool         SetID    = 0;
00148 bool         SetEmail = 0;
00149 bool         SetHost  = 0;
00150 bool         Create   = 0;
00151 bool         Confirm  = 1;
00152 bool         Import   = 0;
00153 bool         Hash     = 1;
00154 bool         ChangePuk = 0;
00155 bool         ChangePwd = 0;
00156 bool         ExportPuk = 0;
00157 
00158 #define NCRYPTMAX 10 // max number of crypto factories
00159 
00160 XrdOucString DefCrypto = "ssl";
00161 XrdOucString CryptList = "";
00162 int          ncrypt    = 0; // number of available crypto factories
00163 XrdOucString CryptMod[NCRYPTMAX] = {""}; // .. and their names
00164 XrdCryptoCipher **RefCip = 0; // .. and their ciphers
00165 XrdCryptoFactory  **CF = 0;
00166 XrdCryptoKDFun_t KDFun = 0;
00167 XrdCryptoKDFunLen_t KDFunLen = 0;
00168 
00169 void Menu(int opt = 0);
00170 int ParseArguments(int argc, char **argv);
00171 void ParseCrypto();
00172 bool CheckOption(XrdOucString opt, const char *ref, int &ival);
00173 bool AddPassword(XrdSutPFEntry &ent, XrdOucString salt,
00174                  XrdOucString &ranpwd,
00175                  bool random, bool checkpw, bool &newpw);
00176 bool AddPassword(XrdSutPFEntry &ent, bool &newpw, const char *pwd = 0);
00177 void SavePasswd(XrdOucString tag, XrdOucString pwd, bool onetime);
00178 bool ReadPasswd(XrdOucString &tag, XrdOucString &pwd, int &st);
00179 bool ReadPuk(int &npuk, XrdOucString *tpuk, XrdOucString *puk);
00180 int GeneratePuk();
00181 bool SavePuk();
00182 bool ReadPuk();
00183 bool ExpPuk(const char *puk = 0, bool read = 1);
00184 bool GetEntry(XrdSutPFile *ff, XrdOucString tag,
00185               XrdSutPFEntry &ent, bool &check);
00186 bool AskConfirm(const char *msg1, bool defact, const char *msg2 = 0);
00187 int LocateFactoryIndex(char *tag, int &id);
00188 
00189 #define PRT(x) {cerr <<x <<endl;}
00190 // Max number of attemps entreing a password
00191 #define kMAXPWDATT 3
00192 
00193 #define kMAXPUK 5
00194 int nHostPuk;
00195 XrdOucString TagHostPuk[kMAXPUK], HostPuk[kMAXPUK];
00196 
00197 int main( int argc, char **argv )
00198 {
00199    // Application for password file administration
00200 
00201 
00202    XrdSutPFEntry ent;
00203    XrdSutPFEntry *nent = 0;
00204    XrdOucString ans = "";
00205    XrdOucString email = "";
00206    XrdOucString uniqueid = "";
00207    XrdOucString tag = "";
00208    XrdOucString prompt = "Password: ";
00209    XrdOucString ranpwd = "";
00210    XrdOucString ImpPwd = "";
00211    XrdOucString salt = "";
00212    const char *pwdimp = 0;
00213    bool checkpwd = 0;
00214    bool newpw = 1;
00215    bool check = 0;
00216    int nr = 0, nm = 0;
00217    int i = 0;
00218    int entst = 0;
00219 
00220    // Parse arguments
00221    if (ParseArguments(argc,argv)) {
00222       exit(0);
00223    }
00224    ParseCrypto();
00225 
00226    // Set trace options
00227    XrdSutSetTrace(sutTRACE_Debug);
00228 
00229    // Attach to file
00230    kXR_int32 openmode = (Create) ? kPFEcreate : 0;
00231    XrdSutPFile ff(File.c_str(), openmode);
00232    if (!ff.IsValid() && ff.LastError() == kPFErrNoFile) {
00233       prompt = "Create file ";
00234       prompt += File;
00235       if (DontAsk || AskConfirm(prompt.c_str(),0)) {
00236          if (Mode == kM_user || Mode == kM_srvpuk)
00237             ff.Init(File.c_str(), kPFEcreate, 0644);
00238          else
00239             ff.Init(File.c_str(), kPFEcreate);
00240       }
00241       if (!ff.IsValid())
00242          exit(1);
00243       if (Mode == kM_admin || Mode == kM_user) {
00244          if (SrvID.length() <= 0) {
00245             if (!DontAsk && AskConfirm("Would you like to enter a server ID? ",1)) {
00246                XrdSutGetLine(SrvID,"Enter ID (max 32 chars): ");
00247                if (SrvID.length() > 32)
00248                   SrvID.erase(32);
00249             } else {
00250                PRT("Server ID will be generated randomly. It can be changed");
00251                PRT("at any time with 'add -srvID <ID>'.");
00252                //
00253                // Set random ID
00254                XrdSutRndm::Init();
00255                XrdSutRndm::GetString(1,8,SrvID);
00256                //
00257                // Add local user name
00258                struct passwd *pw = getpwuid(getuid());
00259                if (pw) {
00260                   SrvID.insert(':',0);
00261                   SrvID.insert(pw->pw_name,0);
00262                }
00263             }
00264          } else if (DontAsk) {
00265             // This is a force creation where no prompt request can be answered
00266             SetID = 0;
00267          }
00268          PRT("Server ID: " << SrvID);
00269          if (SrvID.length() > 0) {
00270             //
00271             // Fill entry
00272             ent.SetName(IDTag.c_str());
00273             ent.status = kPFE_special;
00274             ent.cnt    = 1;
00275             ent.buf1.SetBuf(SrvID.c_str(),SrvID.length()+1);
00276             //
00277             // Write entry
00278             ent.mtime = time(0);
00279             ff.WriteEntry(ent);
00280             PRT(" File successfully created with server ID set to: "
00281                   <<SrvID.c_str());
00282          }
00283          // Generate srvpuk for admin
00284          if (Mode == kM_admin) {
00285 
00286             int ncf = GeneratePuk();
00287             if (ncf != ncrypt)
00288                PRT("// Could generate ref ciphers for all the factories");
00289 
00290             // Update file
00291             for ( i = 0; i < ncrypt; i++ ) {
00292                if (RefCip[i]) {
00293                   //
00294                   // Build tag
00295                   tag = PukTag + '_';
00296                   tag += CF[i]->ID();
00297                   //
00298                   // Serialize in a buffer
00299                   XrdSutBucket *bck = RefCip[i]->AsBucket();
00300                   if (bck) {
00301                      //
00302                      // Prepare Entry
00303                      ent.SetName(tag.c_str());
00304                      ent.status = kPFE_special;
00305                      ent.cnt    = 2;  // protected
00306                      ent.buf1.SetBuf(bck->buffer,bck->size);
00307                      //
00308                      // Write entry
00309                      ent.mtime = time(0);
00310                      ff.WriteEntry(ent);
00311                      PRT(" Server Puk saved for crypto: "<<CF[i]->Name());
00312                      delete bck;
00313                      bck = 0;
00314                   }
00315                }
00316             }
00317             //
00318             // Backup also on separate file
00319             if (!SavePuk()) {
00320                PRT("// Problems with puk backup ");
00321             }
00322          }
00323       } else {
00324          PRT(" File successfully created ");
00325       }
00326    }
00327 
00328    // If admin, check for special entries
00329    // (Server Unique ID, Email, Host name)
00330    if (Mode == kM_admin) {
00331       //
00332       // Ref ciphers
00333       ent.Reset();
00334       nm = ff.SearchEntries(PukTag.c_str(),0);
00335       if (nm) {
00336          int *ofs = new int[nm];
00337          ff.SearchEntries(PukTag.c_str(),0,ofs,nm);
00338          for ( i = 0; i < nm ; i++) {
00339             nr = ff.ReadEntry(ofs[i],ent);
00340             if (nr > 0) {
00341                XrdSutBucket bck;
00342                bck.SetBuf(ent.buf1.buf,ent.buf1.len);
00343                // Locate factory ID
00344                int id = 0;
00345                int ii = LocateFactoryIndex(ent.name, id);
00346                if (ii < 0) {
00347                   PRT("// Factory ID not found: corruption ?");
00348                   exit(1);
00349                }
00350                if (!(RefCip[i] = CF[ii]->Cipher(&bck))) {
00351                   PRT("// Could not instantiate cipher for factory "<<CF[ii]->Name());
00352                   exit(1);
00353                }
00354             }
00355          }
00356       } else {
00357          PRT("// Ref puk ciphers not found: corruption ?");
00358          exit(1);
00359       }
00360 
00361 
00362       if (ff.ReadEntry(IDTag.c_str(),ent) <= 0 && !SetID) {
00363          PRT(" Unique ID missing: 'add -srvID' to set it");
00364       } else if (!SetID) {
00365          SrvID.insert(ent.buf1.buf,0,ent.buf1.len);
00366       }
00367       //
00368       // Unique ID
00369       ent.Reset();
00370       if (ff.ReadEntry(IDTag.c_str(),ent) <= 0 && !SetID) {
00371          PRT(" Unique ID missing: 'add -srvID' to set it");
00372       } else if (!SetID) {
00373          SrvID.insert(ent.buf1.buf,0,ent.buf1.len);
00374       }
00375       //
00376       // Email
00377       ent.Reset();
00378       if (ff.ReadEntry(EmailTag.c_str(),ent) <= 0 && !SetEmail) {
00379          PRT(" Contact E-mail not set: 'add -email <email>' to set it");
00380       } else if (!SetEmail) {
00381          Email.insert(ent.buf1.buf,0,ent.buf1.len);
00382       }
00383       //
00384       // Server Host name 
00385       ent.Reset();
00386       if (ff.ReadEntry(HostTag.c_str(),ent) <= 0 && !SetHost) {
00387          PRT(" Local host name not set: 'add -host <host>' to set it");
00388       } else if (!SetHost) {
00389          SrvName.insert(ent.buf1.buf,0,ent.buf1.len);
00390       }
00391    }
00392 
00393    switch (Action) {
00394    case kA_update:
00395       //
00396       // Like 'add', forcing write
00397       Force = 1;
00398    case kA_add:
00399       //
00400       // Add / Update entry
00401       //
00402       // If admin, check first if we are required to update/create
00403       // some special entry (Server Unique ID, Email, Host Name)
00404       if (Mode == kM_admin) {
00405          //
00406          // Export current Server PUK
00407          if (ExportPuk) {
00408             if (!ExpPuk()) {
00409                PRT("// Could not export public keys");
00410             }
00411             //
00412             // We are done
00413             break;
00414          }
00415          //
00416          // Server PUK
00417          ent.Reset();
00418          if (ChangePuk) {
00419             if (!DontAsk && !AskConfirm("Override server PUK?",0,0))
00420                break;
00421             //
00422             // If we are given a file name, try import from the file
00423             if (Import && PukFile.length() > 0) {
00424                if (!ReadPuk()) {
00425                   PRT("// Problem importing puks from "<<PukFile<<
00426                       " - exit ");
00427                   break;
00428                }
00429             } else {
00430                // Generate new puks
00431                if (GeneratePuk() != ncrypt) {
00432                   PRT("// Could not generate ref ciphers for all the factories");
00433                   break;
00434                }
00435             }
00436             //
00437             // Backup also on separate file
00438             if (!SavePuk()) {
00439                PRT("// Problems with puk backup ");
00440             }
00441             //
00442             // Now shift up the old one(s)
00443             nm = ff.SearchEntries(PukTag.c_str(),0);
00444             if (nm) {
00445                PRT("// Found "<<nm<<" entries for tag '"<<PukTag.c_str()<<
00446                            "' in file: "<<ff.Name());
00447                //
00448                // Book vector for offsets
00449                int *ofs = new int[nm];
00450                //
00451                // Get number of entries related
00452                ff.SearchEntries(PukTag.c_str(),0,ofs,nm);
00453                //
00454                // Read entries now
00455                for ( i = 0; i < nm ; i++) {
00456                   nr = ff.ReadEntry(ofs[i],ent);
00457                   if (nr > 0) {
00458                      //
00459                      // Locate factory ID
00460                      int id;
00461                      int j = LocateFactoryIndex(ent.name,id);
00462                      if (j < 0) break;
00463                      // Serialize in a buffer
00464                      XrdSutBucket *bck = RefCip[j]->AsBucket();
00465                      if (bck) {
00466                         // Shift up buffer content (buf 4 is removed)
00467                         if (ent.buf4.buf)
00468                            delete[] ent.buf4.buf;
00469                         ent.buf4.buf = ent.buf3.buf;
00470                         ent.buf4.len = ent.buf3.len;
00471                         ent.buf3.buf = ent.buf2.buf;
00472                         ent.buf3.len = ent.buf2.len;
00473                         ent.buf2.buf = ent.buf1.buf;
00474                         ent.buf2.len = ent.buf1.len;
00475                         // fill buf 1 with new puk
00476                         ent.buf1.SetBuf(bck->buffer,bck->size);
00477                         //
00478                         // Write entry
00479                         ent.mtime = time(0);
00480                         ff.WriteEntry(ent);
00481                         PRT(" Server Puk updated for crypto: "<<CF[i]->Name());
00482                         delete bck;
00483                         bck = 0;
00484                      }
00485                      //
00486                      // Flag user entries
00487                      char stag[4];
00488                      sprintf(stag,"*_%d",id);
00489                      int nofs = ff.SearchEntries(stag,2);
00490                      if (nofs > 0) {
00491                         int *uofs = new int[nofs];
00492                         ff.SearchEntries(stag,2,uofs,nofs);
00493                         XrdSutPFEntry uent;
00494                         int k = 0, nnr = 0;
00495                         for (; k < nofs; k++) {
00496                            uent.Reset();
00497                            nnr = ff.ReadEntry(uofs[k],uent);
00498                            if (nnr > 0 && !strstr(uent.name,PukTag.c_str())) {
00499                               char c = 0;
00500                               if (uent.buf4.buf) {
00501                                  c = *(uent.buf4.buf);
00502                                  c++;
00503                                  if (c > 4)
00504                                    c = 1;
00505                                  *(uent.buf4.buf) = c;
00506                               } else {
00507                                  uent.buf4.buf = new char[1];
00508                                  uent.buf4.len = 1;
00509                                  *(uent.buf4.buf) = 2;
00510                               }
00511                               // Write entry
00512                               uent.mtime = time(0);
00513                               ff.WriteEntry(uent);
00514                            }
00515                         }
00516                      }
00517                   } else {
00518                      PRT("// warning: problems reading entry: corruption?");
00519                      break;
00520                   }
00521                }
00522             } else {
00523                PRT("// WARNING: No entry for tag '"<<PukTag.c_str()<<
00524                    "' found in file: "<<ff.Name()<<" : corruption? ");
00525                break;
00526             }
00527          }
00528          //
00529          // Server Unique ID
00530          ent.Reset();
00531          if (SetID) {
00532             if (!GetEntry(&ff,IDTag,ent,check)) {
00533                if (!check || AskConfirm("Override server ID?",0,
00534                                         "This may cause inconveniences"
00535                                         " to clients")) {
00536                   //
00537                   // Prepare Entry
00538                   ent.SetName(IDTag.c_str());
00539                   ent.status = kPFE_special;
00540                   ent.cnt    = 1;
00541                   ent.buf1.SetBuf(SrvID.c_str(),SrvID.length()+1);
00542                   //
00543                   // Write entry
00544                   ent.mtime = time(0);
00545                   ff.WriteEntry(ent);
00546                   PRT(" Server ID set to: "<<SrvID.c_str());
00547                }
00548             }
00549          }
00550          //
00551          // Email
00552          ent.Reset();
00553          if (SetEmail) {
00554             if (!GetEntry(&ff,EmailTag,ent,check)) {
00555                if (!check || AskConfirm("Override contact e-mail"
00556                                         " address?",0)) {
00557                   //
00558                   // Prepare Entry
00559                   ent.SetName(EmailTag.c_str());
00560                   ent.status = kPFE_special;
00561                   ent.cnt    = 1;
00562                   ent.buf1.SetBuf(Email.c_str(),Email.length()+1);
00563                   //
00564                   // Write entry
00565                   ent.mtime = time(0);
00566                   ff.WriteEntry(ent);
00567                   PRT(" Contact e-mail set to: "<<Email.c_str());
00568                }
00569             }
00570          }
00571          //
00572          // Server host name
00573          ent.Reset();
00574          if (SetHost) {
00575             if (!GetEntry(&ff,HostTag,ent,check)) {
00576                if (!check || AskConfirm("Override server host name?",0)) {
00577                   //
00578                   // Prepare Entry
00579                   ent.SetName(HostTag.c_str());
00580                   ent.status = kPFE_special;
00581                   ent.cnt    = 1;
00582                   ent.buf1.SetBuf(SrvName.c_str(),SrvName.length()+1);
00583                   //
00584                   // Write entry
00585                   ent.mtime = time(0);
00586                   ff.WriteEntry(ent);
00587                   PRT(" Server host name set to: "<<SrvName.c_str());
00588                }
00589             }
00590          }
00591  
00592       }
00593       //
00594       // If import mode for read info from file
00595       if (Mode == kM_srvpuk) {
00596          if (!Import) {
00597             PRT("// Updating the server puk file requires a file with "<<
00598                 "the keys received by the server administrator:");
00599             PRT("// rerun with option '-import <file_with_keys>' ");
00600             break;
00601          }
00602          if (!ReadPuk(nHostPuk,TagHostPuk,HostPuk))
00603             break;
00604          //
00605          // Now we loop over tags
00606          for (i = 0; i < nHostPuk; i++) {
00607             // Check if not already existing
00608             ent.Reset();
00609             if (GetEntry(&ff,TagHostPuk[i],ent,check)) {
00610                break;
00611             }
00612             // Fill in new puk
00613             ent.buf1.SetBuf(HostPuk[i].c_str(),HostPuk[i].length()+1);
00614             // Write entry
00615             ent.mtime = time(0);
00616             ff.WriteEntry(ent);
00617             if (check) {
00618                PRT("// Server puk "<<TagHostPuk[i]<<" updated");
00619             } else {
00620                PRT("// Server puk "<<TagHostPuk[i]<<" added");
00621             }
00622          }
00623          //
00624          // Browse new content
00625          ff.Browse();
00626          //
00627          // We are done
00628          break;
00629       }
00630       //
00631       // If import mode for read info from file
00632       if (Mode == kM_netrc) {
00633          if (Import) {
00634             if (!ReadPasswd(NameTag,ImpPwd,entst))
00635                break;
00636             pwdimp = ImpPwd.c_str();;
00637          }
00638          // Special treatment for non-hashed passwords (provided
00639          // to allow store info for crypt-like credentials)
00640          if (!Hash) {
00641             // Check if not already existing
00642             ent.Reset();
00643             if (GetEntry(&ff,NameTag,ent,checkpwd)) {
00644                break;
00645             }
00646             // Reset status and cnt
00647             ent.status = entst;
00648             ent.cnt    = 0;
00649             //
00650             // Fill with password
00651             if (!AddPassword(ent, newpw, pwdimp)) {
00652                PRT("Error creating new password: "<<gModesStr[Mode]);
00653                break;
00654             }
00655             //
00656             // Save (or update) entry
00657             ent.mtime = time(0);
00658             ff.WriteEntry(ent);
00659             PRT(" Entry for tag '"<<NameTag<<
00660                 "' created / updated");
00661             // We are done
00662             break;
00663          }
00664       }
00665       //
00666       // Now we need a name tag
00667       if (!NameTag.length()) break;
00668       //
00669       // Ask confirmation, if required
00670       prompt = "Adding/Updating entry for tag: ";
00671       prompt += NameTag;
00672       if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
00673          break;
00674       //
00675       // Normal operations
00676       KDFun = 0;
00677       KDFunLen = 0;
00678       newpw = 1;
00679       //
00680       // New salt (random machinery init only once)
00681       if (Mode != kM_netrc) {
00682          XrdSutRndm::Init();
00683          XrdSutRndm::GetString(3,8,salt);
00684          if (IterNum.length() > 0) {
00685             // Insert non default iteration number in salt
00686             salt.insert(IterNum,0);         
00687          }
00688       }
00689       //
00690       for ( i = 0; i < ncrypt; i++ ) {
00691          // Get hook to crypto factory
00692          CF[i] = XrdCryptoFactory::GetCryptoFactory(CryptMod[i].c_str());
00693          if (!CF[i]) {
00694             PRT("Hook for crypto factory undefined: "<<CryptMod[i].c_str());
00695             break;
00696          }
00697          //
00698          // Get one-way hash function
00699          KDFun = CF[i]->KDFun();
00700          KDFunLen = CF[i]->KDFunLen();
00701          if (!KDFun || !KDFunLen) {
00702             PRT("Error resolving one-way hash functions ");
00703             break;
00704          }
00705          //
00706          // Build tag
00707          tag = NameTag + '_';
00708          tag += CF[i]->ID();
00709          // Check if not already existing
00710          ent.Reset();
00711          if (GetEntry(&ff,tag,ent,checkpwd)) {
00712             break;
00713          }
00714          if (Mode == kM_netrc) {
00715             // If just a request for password change not much to do
00716             if (ChangePwd) {
00717                if (!checkpwd)
00718                   break;
00719                else
00720                   // Update the status
00721                   ent.status = kPFE_onetime;
00722             } else {
00723                // Reset status and cnt
00724                if (pwdimp)
00725                   ent.status = entst;
00726                else
00727                   ent.status = kPFE_ok;
00728                ent.cnt    = 0;
00729                //
00730                // Fill with password
00731                if (!AddPassword(ent, newpw, pwdimp)) {
00732                   PRT("Error creating new password: "<<gModesStr[Mode]);
00733                   break;
00734                }
00735             }
00736          } else {
00737             // Reset cnt
00738             ent.cnt    = 0;
00739             if (Passwd) {
00740                // Set status
00741                ent.status = Change ? kPFE_onetime : kPFE_ok;
00742                //
00743                // Fill with password
00744                if (!AddPassword(ent, salt, ranpwd, Random, checkpwd, newpw)) {
00745                   PRT("Error creating new password: "<<gModesStr[Mode]);
00746                   break;
00747                }
00748             } else {
00749                ent.buf1.SetBuf();
00750                ent.buf2.SetBuf();
00751                ent.buf3.SetBuf();
00752                ent.buf4.SetBuf();
00753                // Just enable entry
00754                ent.status = kPFE_allowed;
00755             }
00756          }
00757          //
00758          // Save (or update) entry
00759          ent.mtime = time(0);
00760          ff.WriteEntry(ent);
00761          PRT(" Entry for tag '"<<tag.c_str()<<
00762              "' created / updated");
00763       }
00764       //
00765       // Save password, if requested
00766       if (SavePw)
00767          SavePasswd(NameTag, ranpwd, Change);
00768 
00769       // Browse the new status
00770       ff.Browse();
00771       break;
00772 
00773    case kA_read:
00774       //
00775       // Get number of entries related
00776       nm = ff.SearchEntries(NameTag.c_str(),0);
00777       PRT("//-----------------------------------------------------"
00778                                              "--------------------//");
00779       PRT("//");
00780       if (nm) {
00781          PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
00782                      "' in file: "<<ff.Name());
00783          //
00784          // Book vector for offsets
00785          int *ofs = new int[nm];
00786          //
00787          // Get number of entries related
00788          ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
00789          //
00790          // Read entries now
00791          for ( i = 0; i < nm ; i++) {
00792             nr = ff.ReadEntry(ofs[i],ent);
00793             if (nr > 0) {
00794                PRT("// #:"<<i+1<<"  "<<ent.AsString());
00795             } else {
00796                PRT("// Entry for ofs "<<ofs[i]<<
00797                      " not found in file: "<<ff.Name());
00798             }
00799          }
00800       } else {
00801          PRT("// No entry for tag '"<<NameTag.c_str()<<
00802                "' found in file: "<<ff.Name());
00803       }
00804       PRT("//");
00805       PRT("//-----------------------------------------------------"
00806                                              "--------------------//");
00807       break;
00808 
00809    case kA_remove:
00810       //
00811       // Ask confirmation, if required
00812       prompt = "Removing entry for tag: ";
00813       prompt += NameTag;
00814       if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
00815          break;
00816       //
00817       // Get number of entries related
00818       nm = ff.SearchEntries(NameTag.c_str(),0);
00819       PRT("//-----------------------------------------------------"
00820                                              "--------------------//");
00821       PRT("//");
00822       if (nm) {
00823          PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
00824                      "' in file: "<<ff.Name());
00825          //
00826          // Book vector for offsets
00827          int *ofs = new int[nm];
00828          //
00829          // Get number of entries related
00830          ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
00831          //
00832          // Read entries now
00833          for ( i = 0; i < nm ; i++) {
00834             if (ff.RemoveEntry(ofs[i]) == 0) {
00835                PRT("// Entry for tag '"<<NameTag.c_str()<<
00836                      "' removed from file: "<<ff.Name());
00837             } else {
00838                PRT("// Entry for tag '"<<NameTag.c_str()<<
00839                      "' not found in file: "<<ff.Name());
00840             }
00841          }
00842       } else {
00843          PRT("// No entry for tag '"<<NameTag.c_str()<<
00844                "' found in file: "<<ff.Name());
00845       }
00846       PRT("//");
00847       PRT("//-----------------------------------------------------"
00848                                              "--------------------//");
00849       break;
00850 
00851    case kA_disable:
00852       //
00853       // Ask confirmation, if required
00854       prompt = "Disabling entry for tag: ";
00855       prompt += NameTag;
00856       if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
00857          break;
00858       //
00859       // Get number of entries related
00860       nm = ff.SearchEntries(NameTag.c_str(),0);
00861       PRT("//-----------------------------------------------------"
00862                                              "--------------------//");
00863       PRT("//");
00864       if (nm) {
00865          PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
00866                      "' in file: "<<ff.Name());
00867          //
00868          // Book vector for offsets
00869          int *ofs = new int[nm];
00870          //
00871          // Get number of entries related
00872          ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
00873          //
00874          // Read entries now
00875          for ( i = 0; i < nm ; i++) {
00876             nr = ff.ReadEntry(ofs[i],ent);
00877             if (nr > 0) {
00878                // Disable entry
00879                ent.status = kPFE_disabled;
00880                ent.cnt = 0;
00881                ent.buf1.SetBuf();
00882                ent.buf2.SetBuf();
00883                ent.buf3.SetBuf();
00884                ent.buf4.SetBuf();
00885                // Save (or update) entry
00886                ent.mtime = time(0);
00887                ff.WriteEntry(ent);
00888                PRT("// Entry for tag '"<<ent.name<<
00889                    "' disabled");
00890             } else {
00891                PRT("// Entry for ofs "<<ofs[i]<<
00892                      " not found in file: "<<ff.Name());
00893             }
00894          }
00895       } else {
00896          PRT("// No entry for tag '"<<NameTag.c_str()<<
00897                "' found in file: "<<ff.Name());
00898       }
00899       PRT("//");
00900       PRT("//-----------------------------------------------------"
00901                                              "--------------------//");
00902       break;
00903 
00904    case kA_copy:
00905       //
00906       // Ask confirmation, if required
00907       prompt = "Copying entry for tag: ";
00908       prompt += NameTag;
00909       prompt += " into tag: ";
00910       prompt += CopyTag;
00911       if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
00912          break;
00913       //
00914       // Ready entry
00915       if (ff.ReadEntry(NameTag.c_str(),ent) <= 0) {
00916          PRT("Entry to copy not found missing");
00917          break;
00918       }
00919       //
00920       // Prepare New Entry
00921       nent = new XrdSutPFEntry(ent);
00922       PRT("//-----------------------------------------------------"
00923                                              "--------------------//");
00924       PRT("//");
00925       if (nent) {
00926          nent->SetName(CopyTag.c_str());
00927          //
00928          // Write entry
00929          nent->mtime = time(0);
00930          ff.WriteEntry(*nent);
00931          PRT("// Entry for tag '"<<nent->name<<
00932              "' created");
00933          delete nent;
00934       } else {
00935          PRT("// Cannot create new entry: out of memory");
00936          break;
00937       }
00938       PRT("//");
00939       PRT("//-----------------------------------------------------"
00940                                              "--------------------//");
00941       break;
00942 
00943    case kA_trim:
00944       //
00945       // Trim the file
00946       ff.Trim();
00947 
00948    case kA_browse:
00949    default:
00950       //
00951       // Browse
00952       ff.Browse();
00953    }
00954 
00955    exit(0);
00956 }
00957 
00958 
00959 void Menu(int opt)
00960 {
00961    // Print the menu
00962    // Options:          0        intro w/  head/tail
00963    //                   1        intro w/o head/tail
00964    //                   2        keywords
00965 
00966    // Head
00967    if (opt == 0) {
00968      PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
00969      PRT("+                                                          +");
00970      PRT("+                  x r d p w d a d m i n                   +");
00971      PRT("+                                                          +");
00972      PRT("+                Administration of pwd files               +");
00973    }
00974 
00975    // Intro
00976    if (opt <= 1) {
00977      PRT("+                                                          +");
00978      PRT("+  Syntax:                                                 +");
00979      PRT("+                                                          +");
00980      PRT("+  xrdpwdadmin [-h] [-m <mode>] [options]                  +");
00981      PRT("+                                                          +");
00982      PRT("+   -h   display this menu                                 +");
00983      PRT("+                                                          +");
00984      PRT("+   -m   choose mode (admin, user, netrc, srvpuk) [admin]  +");
00985      PRT("+                                                          +");
00986      PRT("+        admin:                                            +");
00987      PRT("+        create / modify the main file used by servers     +");
00988      PRT("+        started from this account to validate clients     +");
00989      PRT("+        credentials. Default location and name:           +");
00990      PRT("+                 $(HOME)/.xrd/pwdadmin                    +");
00991      PRT("+                                                          +");
00992      PRT("+        NB: file must readable and writable by owner      +");
00993      PRT("+            only e.g. 0600                                +");
00994      PRT("+                                                          +");
00995      PRT("+        user:                                             +");
00996      PRT("+        create / modify local file used by servers        +");
00997      PRT("+        to validate this user credentials.                +");
00998      PRT("+        Default location and name:                        +");
00999      PRT("+                 $(HOME)/.xrd/pwduser                     +");
01000      PRT("+                                                          +");
01001      PRT("+        NB: the file must be copied on the server machine +");
01002      PRT("+            if produced elsewhere; file must be writable  +");
01003      PRT("+            by the owner only, e.g. 0644                  +");
01004      PRT("+                                                          +");
01005      PRT("+        netrc:                                            +");
01006      PRT("+        create / modify local autologin file              +");
01007      PRT("+        Default location and name:                        +");
01008      PRT("+                 $(HOME)/.xrd/pwdnetrc                    +");
01009      PRT("+                                                          +");
01010      PRT("+        NB: file must readable and writable by owner      +");
01011      PRT("+            only e.g. 0600                                +");
01012      PRT("+                                                          +");
01013      PRT("+        srvpuk:                                           +");
01014      PRT("+        create / modify local file with known server      +");
01015      PRT("+        public cipher initializers.                       +");
01016      PRT("+        Default location and name:                        +");
01017      PRT("+                 $(HOME)/.xrd/pwdsrvpuk                   +");
01018      PRT("+                                                          +");
01019      PRT("+        NB: file must be writable by the owner only       +");
01020      PRT("+            e.g. 0644                                     +");
01021    }
01022 
01023    // Intro
01024    if (opt <= 2) {
01025      PRT("+                                                          +");
01026      PRT("+  Options:                                                +");
01027      PRT("+                                                          +");
01028      PRT("+   add <name> [-[no]force] [-[no]random] [-[no]savepw]    +");
01029      PRT("+      add entry with tag <name>; the application prompts  +");
01030      PRT("+      for the password                                    +");
01031      PRT("+                                                          +");
01032      PRT("+   add <name> -import <pwd_file>                          +");
01033      PRT("+      add entry with tag <name> importing the pwd from    +");
01034      PRT("+      the file send by the server administrator           +");
01035      PRT("+      [netrc only]                                        +");
01036      PRT("+                                                          +");
01037      PRT("+   add -import <srvkey_file>                              +");
01038      PRT("+      add new server key importing the key from           +");
01039      PRT("+      the file send by the server administrator           +");
01040      PRT("+      [srvpuk only]                                       +");
01041      PRT("+                                                          +");
01042      PRT("+   update <name> [options]                                +");
01043      PRT("+      equivalent to 'add -force'                          +");
01044      PRT("+                                                          +");
01045      PRT("+   read <name>                                            +");
01046      PRT("+      list some information of entry associated with tag  +");
01047      PRT("+      <name> (status, count, date of last change, buffer  +");
01048      PRT("+      lengths); buffer contents not listed                +");
01049      PRT("+                                                          +");
01050      PRT("+   remove <name>                                          +");
01051      PRT("+      Make entry associated with tag <name> inactive      +");
01052      PRT("+      (Spce is recovered during next trim operation)      +");
01053      PRT("+                                                          +");
01054      PRT("+   copy <name> <newname>                                  +");
01055      PRT("+      Create new entry with tag <newname> and content of  +");
01056      PRT("+      existing entry with tag <name>                      +");
01057      PRT("+                                                          +");
01058      PRT("+   trim [-nobackup]                                       +");
01059      PRT("+      Trim the file content eliminating all the inactive  +");
01060      PRT("+      entries; a backup is created in <file>.bak unless   +");
01061      PRT("+      the option '-nobackup' is specified                 +");
01062      PRT("+                                                          +");
01063      PRT("+   browse                                                 +");
01064      PRT("+      list a table about the file content                 +");
01065    }
01066 
01067    // Intro
01068    if (opt <= 3) {
01069      PRT("+                                                          +");
01070      PRT("+   -dontask                                               +");
01071      PRT("+      do not prompt for questions: when in doubt use      +");
01072      PRT("+      defaults or fail                                    +");
01073      PRT("+      [default: ask]                                      +");
01074      PRT("+   -force                                                 +");
01075      PRT("+      overwrite entry if it exists already                +");
01076      PRT("+      [default: do not overwrite]                         +");
01077      PRT("+   -[no]change                                            +");
01078      PRT("+      do [not] require user to change info on first use   +");
01079      PRT("+      [default: admin: change / user: no change           +");
01080      PRT("+   -crypto [-]<crypt1>|[-]<crypt2>|...                    +");
01081      PRT("+      create information for the given crypto modules     +");
01082      PRT("+      ('|' separated list) in addition to default ones    +");
01083      PRT("+      (normally ssl and local); use '-' in front to avoid +");
01084      PRT("+      avoid creating a entry for a module; one entry is   +");
01085      PRT("+      for each module with effective tag of the form      +");
01086      PRT("+      name_<cryptoID> [default list: ssl]                 +");
01087      PRT("+                 [default: create backup]                 +");
01088    }
01089 
01090    // Tail
01091    PRT("+                                                          +");
01092    PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01093 }
01094 
01095 int ParseArguments(int argc, char **argv)
01096 {
01097    // Parse application arguments filling relevant global variables
01098    bool changeset = 0;
01099    bool randomset = 0;
01100    bool savepwset = 0;
01101    bool randomid  = 0;
01102 
01103    // Number of arguments
01104    if (argc < 0 || !argv[0]) {
01105       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01106       PRT("+ Insufficient number or arguments!                        +");
01107       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01108       // Print main menu
01109       Menu(0);
01110       return 1;
01111    }
01112    --argc;
01113    ++argv;
01114 
01115    //
01116    // Loop over arguments
01117    while ((argc >= 0) && (*argv)) {
01118 
01119       XrdOucString opt = "";
01120       int ival = -1;
01121       if(*(argv)[0] == '-') {
01122 
01123          opt = *argv;
01124          opt.erase("-"); 
01125          if (CheckOption(opt,"m",ival)) {
01126             if (Mode != kM_undef) {
01127                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01128                PRT("+ Only one valid '-m' option allowed: ignoring             +");
01129                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01130                --argc;
01131                ++argv;
01132                if (argc >= 0 && (*argv && *(argv)[0] == '-')) {
01133                   argc++;
01134                   argv--;
01135                }
01136             }
01137             --argc;
01138             ++argv;
01139             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01140                XrdOucString mode = *argv;
01141                if (CheckOption(mode,"admin",ival)) {
01142                   Mode = kM_admin;
01143                } else if (CheckOption(mode,"user",ival)) {
01144                   Mode = kM_user;
01145                } else if (CheckOption(mode,"netrc",ival)) {
01146                   Mode = kM_netrc;
01147                } else if (CheckOption(mode,"srvpuk",ival)) {
01148                   Mode = kM_srvpuk;
01149                } else if (CheckOption(mode,"help",ival)) {
01150                   Mode = kM_help;
01151                } else {
01152                   PRT("++++++++++++++++++++++++++++++++++++++"
01153                                                  "++++++++++++++++++++++");
01154                   PRT("+ Ignoring unrecognized more: "<<mode.c_str());
01155                   PRT("++++++++++++++++++++++++++++++++++++++"
01156                                                  "++++++++++++++++++++++");
01157                }
01158             } else {
01159                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01160                PRT("+ Option '-m' requires {admin,user,netrc,srvpuk}: ignoring +");
01161                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01162                argc++;
01163                argv--;
01164             }
01165          } else if (CheckOption(opt,"h",ival) ||
01166                     CheckOption(opt,"help",ival) ||
01167                     CheckOption(opt,"menu",ival)) {
01168             Mode = kM_help;
01169          } else if (CheckOption(opt,"f",ival)) {
01170             --argc;
01171             ++argv;
01172             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01173                Path = *argv;
01174             } else {
01175                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01176                PRT("+ Option '-f' requires a file or directory name: ignoring  +");
01177                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01178                argc++;
01179                argv--;
01180             }
01181          } else if (CheckOption(opt,"dontask",ival)) {
01182             DontAsk = ival;
01183          } else if (CheckOption(opt,"force",ival)) {
01184             Force = ival;
01185          } else if (CheckOption(opt,"change",ival)) {
01186             Change = ival;
01187             changeset = 1;
01188          } else if (CheckOption(opt,"passwd",ival)) {
01189             Passwd = ival;
01190          } else if (CheckOption(opt,"backup",ival)) {
01191             Backup = ival;
01192          } else if (CheckOption(opt,"random",ival)) {
01193             Random = ival;
01194             randomset = 1;
01195          } else if (CheckOption(opt,"savepw",ival)) {
01196             SavePw = ival;
01197             savepwset = 1;
01198          } else if (CheckOption(opt,"confirm",ival)) {
01199             Confirm = ival;
01200          } else if (CheckOption(opt,"create",ival)) {
01201             Create = ival;
01202          } else if (CheckOption(opt,"hash",ival)) {
01203             Hash = ival;
01204          } else if (CheckOption(opt,"changepuk",ival)) {
01205             ChangePuk = ival;
01206          } else if (CheckOption(opt,"changepwd",ival)) {
01207             ChangePwd = ival;
01208          } else if (CheckOption(opt,"exportpuk",ival)) {
01209             ExportPuk = ival;
01210          } else if (CheckOption(opt,"iternum",ival)) {
01211             --argc;
01212             ++argv;
01213             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01214                int iter = strtol(*argv,0,10);
01215                if (iter > 0 && errno != ERANGE) {
01216                   IterNum = "$$";
01217                   IterNum += *argv;
01218                   IterNum += "$";
01219                } else {
01220                   PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01221                   PRT("+ Option '-iternum' requires a positive number: ignoring   +");
01222                   PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01223                   argc++;
01224                   argv--;
01225                }
01226             } else {
01227                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01228                PRT("+ Option '-iternum' requires a positive number: ignoring   +");
01229                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01230                argc++;
01231                argv--;
01232             }
01233          } else if (CheckOption(opt,"crypto",ival)) {
01234             --argc;
01235             ++argv;
01236             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01237                CryptList = *argv;
01238             } else {
01239                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01240                PRT("+ Option '-crypto' requires a list of modules: ignoring    +");
01241                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01242                argc++;
01243                argv--;
01244             }
01245          } else if (CheckOption(opt,"import",ival)) {
01246             --argc;
01247             ++argv;
01248             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01249                if (Mode == kM_netrc) {
01250                   PwdFile = *argv;
01251                } else {
01252                   PukFile = *argv;
01253                }
01254                Import = 1;
01255             } else {
01256                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01257                PRT("+ Option '-import' requires a file name: ignoring          +");
01258                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01259                argc++;
01260                argv--;
01261             }
01262          } else if (CheckOption(opt,"srvID",ival)) {
01263             --argc;
01264             ++argv;
01265             SetID = 1;
01266             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01267                SrvID = *argv;
01268             } else {
01269                SrvID = "";
01270                randomid = 1;
01271                argc++;
01272                argv--;
01273             }
01274          } else if (CheckOption(opt,"email",ival)) {
01275             --argc;
01276             ++argv;
01277             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01278                Email = *argv;
01279                SetEmail = 1;
01280             } else {
01281                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01282                PRT("+ Option '-email' requires an email string: ignoring       +");
01283                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01284                argc++;
01285                argv--;
01286             }
01287          } else if (CheckOption(opt,"host",ival)) {
01288             --argc;
01289             ++argv;
01290             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01291                SrvName = *argv;
01292                SetHost = 1;
01293             } else {
01294                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01295                PRT("+ Option '-host' requires the local host name: ignoring    +");
01296                PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01297                argc++;
01298                argv--;
01299             }
01300          } else {
01301             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01302             PRT("+ Ignoring unrecognized option: "<<*argv);
01303             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01304          }
01305 
01306       } else {
01307          //
01308          // Action keyword
01309          opt = *argv;
01310          int iad = -1, iup = -1, ird = -1, irm = -1, idi = -1, icp = -1; 
01311          if (CheckOption(opt,"add",iad) || CheckOption(opt,"update",iup) ||
01312              CheckOption(opt,"read",ird) || CheckOption(opt,"remove",irm) ||
01313              CheckOption(opt,"disable",idi) || CheckOption(opt,"copy",icp)) {
01314             Action = (Action == kA_undef && iad == 1) ? kA_add : Action;
01315             Action = (Action == kA_undef && iup == 1) ? kA_update : Action;
01316             Action = (Action == kA_undef && ird == 1) ? kA_read : Action;
01317             Action = (Action == kA_undef && irm == 1) ? kA_remove : Action;
01318             Action = (Action == kA_undef && idi == 1) ? kA_disable : Action;
01319             Action = (Action == kA_undef && icp == 1) ? kA_copy : Action;
01320             --argc;
01321             ++argv;
01322             if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01323                NameTag = *argv;
01324                if (icp == 1) {
01325                   --argc;
01326                   ++argv;
01327                   if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
01328                      CopyTag = *argv;
01329                   } else {
01330                      PRT("+++++++++++++++++++++++++++++++++++++++++"
01331                                                "+++++++++++++++++++");
01332                      PRT("+ 'copy': missing destination tag: ignoring"
01333                                                  "                +"); 
01334                      PRT("+++++++++++++++++++++++++++++++++++++++++"
01335                                                "+++++++++++++++++++");
01336                      CopyTag = "";
01337                      argc++;
01338                      argv--;
01339                   }
01340                }
01341             } else {
01342                NameTag = "";
01343                argc++;
01344                argv--;
01345             }
01346          } else if (CheckOption(opt,"trim",ival)) {
01347             Action = kA_trim;
01348          } else if (CheckOption(opt,"browse",ival)) {
01349             Action = kA_browse;
01350          } else {
01351             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01352             PRT("+ Ignoring unrecognized keyword action: "<<opt.c_str());
01353             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01354          }
01355       }
01356       --argc;
01357       ++argv;
01358    }
01359 
01360    //
01361    // Default mode 'admin'
01362    Mode = (Mode == 0) ? kM_admin : Mode;
01363 
01364    //
01365    // If help mode, print menu and exit
01366    if (Mode == kM_help) {
01367       // Print main menu
01368       Menu(0);
01369       return 1;
01370    }
01371 
01372    //
01373    // Some action need a tag name
01374    bool special = SetID || SetEmail || SetHost || ChangePuk || ExportPuk;
01375    if (Action == kA_add || Action == kA_update ||
01376        Action == kA_read || Action == kA_remove) {
01377       if (!special && !NameTag.length() &&!Import) {
01378          PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01379          PRT("+ Specified action requires a tag: "<<
01380                 gActionsStr[Action]);
01381          PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01382          Menu(2);
01383          return 1;
01384       }
01385    }
01386 
01387    //
01388    // If user mode, check if NameTag contains the local user
01389    // name: if not, warn the user about possible problems with
01390    // servers ignoring this kind of entries for users files
01391    if (Mode == kM_admin && SetID) {
01392       if (randomid) {
01393          // Set random ID
01394          XrdSutRndm::Init();
01395          XrdSutRndm::GetString(1,8,SrvID);
01396          // Add local user name
01397          struct passwd *pw = getpwuid(getuid());
01398          if (pw) {
01399             SrvID.insert(':',0);
01400             SrvID.insert(pw->pw_name,0);
01401          } else { 
01402             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01403             PRT("+ WARNING: could not get local user info for srv ID        +");
01404             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01405          }
01406       } else {
01407          if (SrvID.length() > 32) {
01408             SrvID.erase(32);
01409             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01410             PRT("+ WARNING: srv ID too long: truncating to 32 chars: "
01411                    <<SrvID.c_str());
01412             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01413          }
01414       }
01415    }
01416 
01417    //
01418    // Setting a non default iteration number is only allowed
01419    // in admin or user mode, to avoid potential inconsistencies
01420    if (IterNum.length() > 0 && (Mode != kM_admin && Mode != kM_user)) {
01421       IterNum = "";
01422       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01423       PRT("+ WARNING: ignore iter num change request (not admin/user) +");
01424       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01425    }
01426 
01427    //
01428    // Requesting a password change only makes sense in netrc mode
01429    if (ChangePwd && Mode != kM_netrc) {
01430       ChangePwd = 0;
01431       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01432       PRT("+ WARNING: ignore password change request (not netrc)      +");
01433       PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01434    }
01435 
01436    //
01437    // If user mode, check if NameTag contains the local user
01438    // name: if not, warn the user about possible problems with
01439    // servers ignoring this kind of entries for users files
01440    if (Mode == kM_user && NameTag.length()) {
01441       struct passwd *pw = getpwuid(getuid());
01442       if (pw) {
01443          XrdOucString locusr = pw->pw_name;
01444          if (NameTag != locusr) {
01445             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01446             PRT("+ WARNING: name tag does not match local user name: ");
01447             PRT("+          "<<NameTag.c_str()<<"  "<<locusr.c_str());
01448             PRT("+ Some servers may ignore this entry ");
01449             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01450             if (Action == kA_add)
01451                Confirm = 1; 
01452          }
01453       }
01454    }
01455 
01456    //
01457    // Default action 'browse', except for specials
01458    Action = (Action == kA_undef && special) ? kA_add : Action;
01459    Action = (Action == kA_undef) ? kA_browse : Action;
01460 
01461    //
01462    // Set defaults according to mode, if required
01463    if (Mode == kM_admin) {
01464       Change = (changeset) ? Change : 1;
01465       Random = (randomset) ? Random : 1;
01466       SavePw = (savepwset) ? SavePw : 1;
01467    } else {
01468       Change = (changeset) ? Change : 0;
01469       Random = (randomset) ? Random : 0;
01470       SavePw = (savepwset) ? SavePw : 0;
01471    }
01472 
01473    //
01474    // 'Create' can be active only for 'add' or 'update'
01475    Create = (Action == kA_add || Action == kA_update) ? Create : 0;
01476 
01477    //
01478    // If defined, check nature of Path (if it exists)
01479    if (Path.length()) {
01480       //
01481       // Expand Path
01482       XrdSutExpand(Path);
01483       // Get info
01484       struct stat st;
01485       if (stat(Path.c_str(),&st) == 0) {
01486          if (S_ISDIR(st.st_mode)) {
01487             // Directory
01488             Dir = Path;
01489          } else {
01490             // Regular file
01491             File = Path;
01492          }
01493       } else {
01494          if (errno == ENOENT) {
01495             // Path does not exist: assume this is the wanted file
01496             File = Path;
01497          } else {
01498             // Path exists but we cannot access it - exit
01499             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01500             PRT("+ Cannot access requested path: "<<Path.c_str());
01501             PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01502             return 1;
01503          }
01504       }
01505    }
01506 
01507    // Default File, if not specified
01508    if (!File.length()) {
01509       if (!Dir.length())
01510          Dir = DirRef;
01511       // Expand File
01512       XrdSutExpand(Dir);
01513       File = Dir;
01514       // Make the directory, if needed
01515       if (XrdSutMkdir(File.c_str(),0777) != 0) {
01516          PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01517          PRT("+ Cannot create requested path: "<<File.c_str());
01518          PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
01519          return 1;
01520       }
01521       // Define the files
01522       if (Mode == kM_admin) {
01523          File += AdminRef;
01524       } else if (Mode == kM_user) {
01525          File += UserRef;
01526       } else if (Mode == kM_netrc) {
01527          File += NetRcRef;
01528       } else if (Mode == kM_srvpuk) {
01529          File += SrvPukRef;
01530       }
01531    }
01532 
01533    return 0;
01534 }
01535 
01536 void ParseCrypto()
01537 {
01538    // Parse crypto information in globals to load relevant factories
01539 
01540    // Use defaults if no special argument was entered
01541    if (CryptList == "")
01542       CryptList = DefCrypto;
01543 
01544    //
01545    // Vectorize
01546    int from = 0;
01547    while ((from = CryptList.tokenize(CryptMod[ncrypt], from, '|')) != -1
01548            && ncrypt < NCRYPTMAX) {
01549       ncrypt++;
01550    } 
01551    RefCip = new XrdCryptoCipher *[ncrypt];
01552    CF = new XrdCryptoFactory *[ncrypt];
01553    if (CF) {
01554       int i = 0;
01555       for (; i < ncrypt; i++ ) {
01556          // Get hook to crypto factory
01557          CF[i] = XrdCryptoFactory::GetCryptoFactory(CryptMod[i].c_str());
01558          if (!CF[i]) {
01559             PRT("// Hook for crypto factory "<<CryptMod[i]<<" undefined");
01560             continue;
01561          }
01562       }
01563    }
01564 }
01565 
01566 bool CheckOption(XrdOucString opt, const char *ref, int &ival)
01567 {
01568    // Check opt against ref
01569    // Return 1 if ok, 0 if not
01570    // Fills ival = 1 if match is exact
01571    //       ival = 0 if match is exact with no<ref> 
01572    //       ival = -1 in the other cases
01573    bool rc = 0;
01574 
01575    int lref = (ref) ? strlen(ref) : 0;
01576    if (!lref) 
01577       return rc;
01578    XrdOucString noref = ref;
01579    noref.insert("no",0);
01580 
01581    ival = -1;
01582    if (opt == ref) {
01583       ival = 1;
01584       rc = 1;
01585    } else if (opt == noref) {
01586       ival = 0;
01587       rc = 1;
01588    }
01589 
01590    return rc;
01591 }
01592 
01593 bool AddPassword(XrdSutPFEntry &ent, XrdOucString salt, XrdOucString &ranpwd,
01594                  bool random, bool checkpw, bool &newpw)
01595 {
01596    // Generate (prompting or randomly) new password and add it
01597    // to entry ent
01598    // If checkpw, make sure that it is different from the existing
01599    // one (check is done on the hash, cannot decide if the change
01600    // is significant or not).
01601    // Return generated random password in ranpwd.
01602    // Randoms passwords are 8 char lengths filled with upper and
01603    // lower case letters and numbers  
01604    // If !newpw, the a pwd saved during a previous call is used,
01605    // if any.
01606    // Return 1 if ok, 0 otherwise.
01607    static XrdOucString pwdref;
01608 
01609    XrdSutPFBuf oldsalt;
01610    XrdSutPFBuf oldhash;
01611    //
01612    // Save existing salt and hash, if required
01613    if (checkpw) {
01614       if (ent.buf1.len > 0 && ent.buf1.buf) {
01615          oldsalt.SetBuf(ent.buf1.buf,ent.buf1.len);
01616          if (ent.buf2.len > 0 && ent.buf2.buf) {
01617             oldhash.SetBuf(ent.buf2.buf,ent.buf2.len);
01618          } else {
01619             checkpw = 0;
01620          }
01621       } else {
01622          checkpw = 0;
01623       }
01624    }
01625    //
01626    // Save salt
01627    ent.buf1.SetBuf(salt.c_str(),salt.length());
01628    //
01629    // Prepare to get password
01630    XrdOucString passwd = "";
01631    if (newpw || !pwdref.length()) {
01632       newpw = 1;
01633       pwdref = "";
01634    }
01635    char *pwhash = 0;
01636    int pwhlen = 0;
01637    int natt = 0;
01638    while (!passwd.length()) {
01639       //
01640       //
01641       if (natt == kMAXPWDATT) {
01642          PRT("AddPassword: max number of attempts reached: "<<kMAXPWDATT);
01643          if (pwhash) delete[] pwhash;
01644          return 0;
01645       }
01646       //
01647       // Inquire password
01648       if (newpw) {
01649          if (!random) {
01650             XrdOucString prompt = "Password: ";
01651             if (natt == (kMAXPWDATT - 1))
01652                prompt.insert(" (last attempt)",prompt.find(":"));
01653             XrdSutGetPass(prompt.c_str(), passwd);
01654             if (passwd.length()) {
01655                pwdref = passwd;
01656                if (SavePw)
01657                   ranpwd = passwd;
01658                newpw = 0;
01659             } else {
01660                natt++;
01661                break;
01662             }
01663          } else if (random) {
01664             XrdSutRndm::GetString(1,8,passwd);
01665             if (IterNum.length() > 0) {
01666                // Set a non-default iteration number (we are going to hash
01667                // the password with itself)
01668                passwd.insert(IterNum,0);
01669             }
01670             pwdref = passwd;
01671             ranpwd = passwd;
01672             newpw = 0;
01673             checkpw = 0; // not needed
01674          }
01675       } else {
01676          passwd = pwdref;
01677       }
01678       // Get pw hash encoding password with itself
01679       pwhash = new char[(*KDFunLen)()];
01680       pwhlen = (*KDFun)(passwd.c_str(),passwd.length(),
01681                         passwd.c_str(),passwd.length(),pwhash,0);
01682       //
01683       // Check the password if required
01684       if (checkpw) {
01685          // Get hash with old salt
01686          char *osahash = new char[(*KDFunLen)()];
01687          // Encode the pw hash with the salt
01688          (*KDFun)(pwhash,pwhlen,
01689                   oldsalt.buf,oldsalt.len,osahash,0);
01690          if (!memcmp(oldhash.buf,osahash,oldhash.len)) {
01691             // Do not accept this password
01692             PRT("AddPassword: Password seems to be the same"
01693                   ": please enter a different one");
01694             passwd.hardreset();
01695             pwdref.hardreset();
01696             ranpwd.hardreset();
01697             newpw = 1;
01698          }
01699          // Cleanup
01700          if (osahash) delete[] osahash;
01701       }
01702    }
01703    //
01704    // Calculate new hash, now
01705    if (passwd.length()) {
01706       // Get new hash
01707       char *nsahash = new char[(*KDFunLen)()];
01708       // Encode first the hash with the salt
01709       int hlen = (*KDFun)(pwhash,pwhlen,
01710                           salt.c_str(),salt.length(),nsahash,0);
01711       // Copy result in buf 2
01712       ent.buf2.SetBuf(nsahash,hlen);
01713       // Cleanup
01714       if (nsahash) delete[] nsahash;
01715    }
01716    //
01717    // Cleanup
01718    if (pwhash) delete[] pwhash;
01719    // We are done
01720    return 1;
01721 }
01722 
01723 bool AddPassword(XrdSutPFEntry &ent, bool &newpw, const char *pwd)
01724 {
01725    // Prompt new password and save in hash form to entry ent
01726    // (if pwd is defined, take password from pwd). 
01727    // If !newpw, the a pwd saved during a previous call is used,
01728    // if any.
01729    // Return 1 if ok, 0 otherwise.
01730    static XrdOucString pwdref;
01731 
01732    //
01733    // Prepare to get passwrod
01734    XrdOucString passwd = "";
01735    if (newpw || !pwdref.length()) {
01736       newpw = 1;
01737       pwdref = "";
01738    }
01739    //
01740    // If we are given a password, use it
01741    if (pwd && strlen(pwd) > 0) {
01742       PRT("AddPassword: using input password ("<<strlen(pwd)<<" bytes)");
01743       passwd = pwd;
01744    }
01745    char *pwhash = 0;
01746    int pwhlen = 0;
01747    int natt = 0;
01748    while (!passwd.length()) {
01749       //
01750       //
01751       if (natt == kMAXPWDATT) {
01752          PRT("AddPassword: max number of attempts reached: "<<kMAXPWDATT);
01753          if (pwhash) delete[] pwhash;
01754          return 0;
01755       }
01756       //
01757       // Inquire password
01758       if (newpw) {
01759          XrdOucString prompt = "Password: ";
01760          if (natt == (kMAXPWDATT - 1))
01761             prompt.insert(" (last attempt)",prompt.find(":"));
01762          XrdSutGetPass(prompt.c_str(), passwd);
01763          if (passwd.length()) {
01764             pwdref = passwd;
01765             newpw = 0;
01766          } else {
01767             natt++;
01768             break;
01769          }
01770       } else {
01771          passwd = pwdref;
01772       }
01773    }
01774    //
01775    // Get pw hash encoding password with itself
01776    if (Hash) {
01777       pwhash = new char[(*KDFunLen)()];
01778       pwhlen = (*KDFun)(passwd.c_str(),passwd.length(),
01779                         passwd.c_str(),passwd.length(),pwhash,0);
01780    } else {
01781       // Provided for backward compatibility with crypt-like
01782       // password hash: we just store the password in this case
01783       pwhlen = passwd.length();
01784       pwhash = new char[pwhlen];
01785       memcpy(pwhash,passwd.c_str(),pwhlen);
01786    }
01787    //
01788    // Save result in buf 1
01789    ent.buf1.SetBuf(pwhash,pwhlen);
01790    //
01791    // Cleanup
01792    if (pwhash) delete[] pwhash;
01793    // We are done
01794    return 1;
01795 }
01796 
01797 void SavePasswd(XrdOucString tag, XrdOucString pwd, bool onetime)
01798 {
01799    // Save password pwd for tag in file
01800    
01801    // Make sure we gor something
01802    if (!tag.length() || !pwd.length()) {
01803       PRT("SavePasswd: tag or pwd undefined - do nothing ("<<
01804           tag.c_str()<<","<<pwd.c_str()<<")");
01805       return;
01806    }
01807    // Make sure the directory exists, first
01808    if (!Dir.length()) {
01809       PRT("SavePasswd: main directory undefined - do nothing");
01810       return;
01811    }
01812    //
01813    // Define passwd dir
01814    PwdFile = Dir;
01815    PwdFile += GenPwdRef;
01816    //
01817    // Make the directory, if needed
01818    if (XrdSutMkdir(PwdFile.c_str(),0777) != 0) {
01819       PRT("SavePasswd: Cannot create requested path: "<<PwdFile.c_str());
01820       return;
01821    }
01822    //
01823    // File name
01824    PwdFile += tag;
01825    //
01826    // Open file, truncating if it exists already
01827    int fd = open(PwdFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
01828    if (fd < 0) {
01829       PRT("SavePasswd: could not open/create file: "<<PwdFile.c_str());
01830       PRT("SavePasswd: errno: "<<errno);
01831       return;
01832    }
01833    //
01834    // Generate buffer
01835    XrdOucString buf;
01836    buf += "********* Password information **************\n\n";
01837    buf += "host:     "; buf += SrvName; buf += "\n";
01838    buf += "ID:       "; buf += SrvID; buf += "\n";
01839    buf += "tag:      "; buf += tag; buf += "\n";
01840    buf += "password: "; buf += pwd; buf += "\n";
01841    if (onetime) {
01842       buf += "status:   "; buf += 2; buf += "\n";
01843       buf += "\n";
01844       buf += "NB: one-time password: user will be asked for \n";
01845       buf += "    new password on first login               \n";
01846    } else {
01847       buf += "status:   "; buf += 1; buf += "\n";
01848       buf += "\n";
01849    }
01850    buf += "*********************************************";
01851    //
01852    // Write it to file
01853       // Now write the buffer to the stream
01854    while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
01855       errno = 0;
01856    //
01857    // Generate buffer
01858    buf.assign("\n",0);
01859    buf += "********* Server PUK information **************\n\n";
01860    int i = 0;
01861    for (; i < ncrypt; i++) {
01862       XrdOucString ptag = SrvName + ":";
01863       ptag += SrvID; ptag += "_"; ptag += CF[i]->ID();
01864       buf += "puk:      "; buf += ptag; buf += "\n";
01865       int lpub = 0;
01866       char *pub = RefCip[i]->Public(lpub);
01867       if (pub) {
01868          buf += pub; buf += "\n";
01869          delete[] pub;
01870       }
01871       buf += "epuk\n";
01872    }
01873    buf += "\n";
01874    buf += "*********************************************";
01875    //
01876    // Write it to file
01877       // Now write the buffer to the stream
01878    while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
01879       errno = 0;
01880    //
01881    // Close file
01882    close (fd);
01883 
01884    // We are done
01885    return;
01886 }
01887 
01888 bool GetEntry(XrdSutPFile *ff, XrdOucString tag,
01889               XrdSutPFEntry &ent, bool &check)
01890 {
01891    // Get antry from file, checking force
01892    // Returns 1 if it exists and should not be updated
01893    // 0 otherwise
01894 
01895    int nr = ff->ReadEntry(tag.c_str(),ent);
01896    check = 0;
01897    if (nr > 0) {
01898       if (!Force) {
01899          PRT(" Entry for tag '"<<tag.c_str()<<
01900                "' already existing in file: "<<ff->Name());
01901          PRT(" Details: "<<ent.AsString());
01902          PRT(" Use option '-force' to overwrite / update");
01903          return 1;
01904       } else {
01905          check = 1;
01906       }
01907    } else {
01908       //
01909       // Prepare Entry
01910       ent.SetName(tag.c_str());
01911       ent.cnt    = 0;
01912    }
01913    return 0;
01914 }
01915 
01916 bool AskConfirm(const char *msg1, bool defact, const char *msg2)
01917 {
01918    // Prompt for confirmation of action
01919    // If defined, msg1 is printed as prompt, followed by the default action
01920    // (  [y] == do-act, for defact = true; 
01921    //    [n] == do-not-act, for defact = false)
01922    // If defined, msg2 is printed before prompting.
01923 
01924    bool rc = defact;
01925 
01926    if (!Confirm) {
01927       rc = 1;
01928    } else {
01929       if (msg2) PRT(msg2);
01930       XrdOucString ask;
01931       XrdOucString prompt = defact ? " [y]: " : " [n]: ";
01932       if (msg1)
01933          prompt.insert(msg1,0);
01934       XrdSutGetLine(ask,prompt.c_str());
01935       ask.lower(0);
01936       if (ask.length()) {
01937          if (defact && (ask == 'n' || ask == "no")) {
01938             rc = 0;
01939          } else if (!defact && (ask == 'y' || ask == "yes")) {
01940             rc = 1;
01941          }
01942       }
01943    }
01944    // we are done
01945    return rc;
01946 }
01947 
01948 bool ReadPasswd(XrdOucString &tag, XrdOucString &pwd, int &st)
01949 {
01950    // Read info from file PwdFile
01951    // Return tag in the form '<user>@<host><srvID>' and associated password
01952    
01953    // Make sure that the filename is defined
01954    if (PwdFile.length() <= 0) {
01955       PRT("ReadPasswd: file name undefined - do nothing");
01956       return 0;
01957    }
01958    //
01959    // Open file in read mode
01960    FILE *fd = fopen(PwdFile.c_str(),"r");
01961    if (fd == 0) {
01962       PRT("ReadPasswd: could not open file: "<<PwdFile.c_str());
01963       PRT("ReadPasswd: errno: "<<errno);
01964       return 0;
01965    }
01966    //
01967    // Read and process the info, now
01968    XrdOucString usr, host, id;
01969    char line[1024], s1[50], s2[1024];
01970    while (fgets(line, sizeof(line), fd) != 0) {
01971       if (line[strlen(line)-1] == '\n')
01972          line[strlen(line)-1] = 0;
01973       if (strlen(line) <= 0)
01974          continue;
01975       if (sscanf(line,"%s %s",s1,s2) < 2)
01976          continue;
01977       if (!strncmp(s1,"host:",5)) {
01978          host = s2;
01979       } else if (!strncmp(s1,"ID:",3)) {
01980          id = s2;
01981       } else if (!strncmp(s1,"tag:",4)) {
01982          usr = s2;
01983       } else if (!strncmp(s1,"password:",9)) {
01984          pwd = s2;
01985       } else if (!strncmp(s1,"status:",7)) {
01986          st = strtol(s2, 0, 10);
01987       }
01988    }
01989    //
01990    // Close file
01991    fclose(fd);
01992    //
01993    // Check if we found all the essential information
01994    if (usr.length() <= 0 || pwd.length() <= 0) {
01995       if (usr.length() <= 0)
01996          PRT("ReadPasswd: usr tag missing in file "<<PwdFile.c_str());
01997       if (pwd.length() <= 0)
01998          PRT("ReadPasswd: password missing in file "<<PwdFile.c_str());
01999       return 0;
02000    }
02001    //
02002    // Warning if some other information is missing
02003    if (host.length() <= 0 || id.length() <= 0) {
02004       if (host.length() <= 0)
02005          PRT("ReadPasswd: warning: host name missing in file "
02006              <<PwdFile);
02007       if (id.length() <= 0)
02008          PRT("ReadPasswd: warning: srv ID missing in file "
02009              <<PwdFile);
02010    }
02011    //
02012    // Build tag
02013    tag = usr;
02014    //
02015    // Add host, if any
02016    if (host.length() > 0) {
02017       tag += '@';
02018       tag += host;
02019       tag += ':';
02020    }
02021    //
02022    // Add srv ID, if any
02023    if (id.length() > 0) {
02024       tag += id;
02025    }
02026    //
02027    // Notify tag
02028    PRT("ReadPasswd: build tag: "<<tag);
02029 
02030 
02031    // We are done
02032    return 1;
02033 }
02034 
02035 bool ReadPuk(int &ipuk, XrdOucString *tpuk, XrdOucString *puk)
02036 {
02037    // Read server puks from file PwdFile
02038    // Return tags in the form '<host>:<srvID>_<cf_id>'
02039    
02040    // Make sure that the filename is defined
02041    if (PukFile.length() <= 0) {
02042       PRT("ReadPuk: file name undefined - do nothing");
02043       return 0;
02044    }
02045    //
02046    // Open file in read mode
02047    FILE *fd = fopen(PukFile.c_str(),"r");
02048    if (fd == 0) {
02049       PRT("ReadPuk: could not open file: "<<PukFile.c_str());
02050       PRT("ReadPuk: errno: "<<errno);
02051       return 0;
02052    }
02053    //
02054    // Read and process the info, now
02055    ipuk = 0;
02056    char line[1024], s1[50], s2[1024];
02057    while (fgets(line, sizeof(line), fd) != 0) {
02058       if (line[strlen(line)-1] == '\n')
02059          line[strlen(line)-1] = 0;
02060       if (strlen(line) <= 0)
02061          continue;
02062       if (sscanf(line,"%s %s",s1,s2) < 2)
02063          continue;
02064       if (!strncmp(s1,"puk:",4)) {
02065          if (ipuk < kMAXPUK) {
02066             tpuk[ipuk] = s2;
02067             while (fgets(line, sizeof(line), fd) != 0) {
02068                if (!strncmp(line,"puk:",4) ||
02069                    !strncmp(line,"epuk",4) || strlen(line) <= 0)
02070                   break;
02071                puk[ipuk] += line;
02072             }
02073             ipuk++;
02074          } else {
02075             PRT("ReadPuk: warning: max number of puks reached ("<<kMAXPUK<<")");
02076          }
02077       }
02078    }
02079    //
02080    // Close file
02081    fclose(fd);
02082    //
02083    // Build puk tags
02084    PRT("ReadPuk: found "<<ipuk<<" server puks");
02085    int i = 0;
02086    for (; i < ipuk; i++) {
02087       //
02088       // Notify tag
02089       PRT("ReadPuk: build puk tag: "<<tpuk[i]);
02090    }
02091 
02092    // We are done
02093    return 1;
02094 }
02095 
02096 bool SavePuk()
02097 {
02098    // Save ref ciphers in file named after GenPukRef and a date string
02099 
02100    // Make sure the directory exists, first
02101    if (!Dir.length()) {
02102       PRT("SavePuk: main directory undefined - do nothing");
02103       return 0;
02104    }
02105    //
02106    // Define passwd dir
02107    PukFile = Dir;
02108    PukFile += GenPukRef;
02109    //
02110    // Make the directory, if needed
02111    if (XrdSutMkdir(PukFile.c_str(),0777) != 0) {
02112       PRT("SavePuk: Cannot create requested path: "<<PukFile);
02113       return 0;
02114    }
02115    //
02116    // File name
02117    PukFile += "puk.";
02118    int now = time(0);
02119    char *tstr = new char[20];
02120    if (!tstr) {
02121       PRT("SavePuk: Cannot create buffer for time string");
02122       return 0;
02123    }
02124    XrdSutTimeString(now, tstr, 1);
02125    PukFile += tstr;
02126    delete tstr;
02127    //
02128    // Open file, truncating if it exists already
02129    int fd = open(PukFile.c_str(),O_WRONLY | O_CREAT | O_TRUNC, 0600);
02130    if (fd < 0) {
02131       PRT("SavePuk: could not open/create file: "<<PukFile);
02132       PRT("SavePuk: errno: "<<errno);
02133       return 0;
02134    }
02135    //
02136    // Temporary array of buckets
02137    XrdSutBucket **bck = new XrdSutBucket *[ncrypt];
02138    if (!bck) {
02139       PRT("SavePuk: Cannot create array of temporary buckets");
02140       return 0;
02141    }
02142    //
02143    // First loop over ciphers to determine the size
02144    int lout = 0, i = 0;
02145    for (; i < ncrypt; i++) {
02146       //
02147       // Make sure it is defined
02148       if (!CF[i] || !RefCip[i]) continue;
02149       //
02150       // Get bucket out of cipher
02151       bck[i] = RefCip[i]->AsBucket();
02152       if (!bck[i]) continue;
02153       //
02154       // Count
02155       lout += (bck[i]->size + 2*sizeof(kXR_int32));
02156    }
02157    //
02158    // Get the buffer
02159    char *bout = new char[lout];
02160    if (!bout) {
02161       PRT("SavePuk: Cannot create output buffer");
02162       close(fd);
02163       return 0;
02164    }
02165    //
02166    // Loop over ciphers to fill the buffer
02167    int lp = 0;
02168    for (i = 0; i < ncrypt; i++) {
02169       //
02170       // Make sure it is defined
02171       if (!CF[i] || !bck[i]) continue;
02172       //
02173       // The crypto ID first
02174       kXR_int32 id = CF[i]->ID();
02175       memcpy(bout+lp,&id,sizeof(kXR_int32));
02176       lp += sizeof(kXR_int32);
02177       //
02178       // The length second
02179       kXR_int32 lpuk = bck[i]->size;
02180       memcpy(bout+lp,&lpuk,sizeof(kXR_int32));
02181       lp += sizeof(kXR_int32);
02182       //
02183       // Finally the content
02184       memcpy(bout+lp,bck[i]->buffer,lpuk);
02185       lp += lpuk;
02186       //
02187       // Cleanup
02188       delete bck[i];
02189       bck[i] = 0;
02190    }
02191    delete[] bck;
02192    //
02193    // Write it to file
02194       // Now write the buffer to the stream
02195    while (write(fd, bout, lout) < 0 && errno == EINTR)
02196       errno = 0;
02197    PRT("SavePuk: "<<lout<<" bytes written to file "<<PukFile);
02198    //
02199    // Close file
02200    close (fd);
02201 
02202    // We are done
02203    return 1;
02204 }
02205 
02206 bool ReadPuk()
02207 {
02208    // Read ref ciphers from file PukFile
02209    
02210    // Make sure that the filename is defined
02211    if (PukFile.length() <= 0) {
02212       PRT("ReadPuk: file name undefined - do nothing");
02213       return 0;
02214    }
02215    //
02216    // Open file in read mode
02217    int fd = open(PukFile.c_str(),O_RDONLY);
02218    if (fd < 0) {
02219       PRT("ReadPuk: could not open file: "<<PukFile.c_str());
02220       PRT("ReadPuk: errno: "<<errno);
02221       return 0;
02222    }
02223 
02224    //
02225    // Read out info now
02226    int nr = 0, nrdt = 0, ncip = 0;
02227    kXR_int32 id = 0, lpuk = 0;
02228    // the status ...
02229    while ((nr = read(fd,&id,sizeof(kXR_int32))) == sizeof(kXR_int32)) {
02230       nrdt += nr;
02231       // Read puk length
02232       if ((nr = read(fd,&lpuk,sizeof(kXR_int32))) != sizeof(kXR_int32)) {
02233          PRT("ReadPuk: could not read puk length - corrupton ? ");
02234          close(fd);
02235          return 0;
02236       }
02237       nrdt += nr;
02238       // Read puk buffer
02239       char *puk = new char[lpuk];
02240       if (!puk) {
02241          PRT("ReadPuk: could not allocate buffer for puk");
02242          close(fd);
02243          return 0;
02244       }
02245       if ((nr = read(fd, puk, lpuk)) != lpuk) {
02246          PRT("ReadPuk: could not read puk buffer - corrupton ? ");
02247          close(fd);
02248          return 0;
02249       }
02250       nrdt += nr;
02251       // Save in bucket
02252       XrdSutBucket *bck = new XrdSutBucket(puk, lpuk);
02253       if (!bck) {
02254          PRT("ReadPuk: could not create bucket for puk");
02255          delete[] puk;
02256          close(fd);
02257          return 0;
02258       }
02259       // Find crypto factory index
02260       int i = ncrypt - 1;
02261       while (i >= 0) {
02262          if (CF[i] && CF[i]->ID() == id) break;
02263          i--;
02264       }
02265       if (i < 0) {
02266          PRT("ReadPuk: warning: factory with ID "<< id << " not found");
02267          delete bck;
02268          continue;        
02269       }
02270       // Instantiate cipher from bucket
02271       RefCip[i] = CF[i]->Cipher(bck);     
02272       if (!RefCip[i]) {
02273          PRT("ReadPuk: warning: could not instantiate cipher"
02274              " from bucket for factory "<<CF[i]->Name());
02275       } else {
02276          PRT("ReadPuk: instantiate cipher for factory "<<CF[i]->Name());
02277       }
02278       // Count good ciphers
02279       ncip++;
02280       delete bck;
02281    }
02282    //
02283    // Close file
02284    close (fd);
02285 
02286    PRT("ReadPuk: "<<nrdt<<" bytes read from file "<<PukFile);
02287    PRT("ReadPuk: "<<ncip<<" ciphers instantiated");
02288 
02289    // We are done
02290    return 1;
02291 }
02292 
02293 int GeneratePuk()
02294 {
02295    // Generate new ref ciphers for all the defined factories
02296    
02297    int ncf = 0, i = 0;
02298    for (; i < ncrypt; i++ ) {
02299       // Get hook to crypto factory
02300       CF[i] = XrdCryptoFactory::GetCryptoFactory(CryptMod[i].c_str());
02301       if (!CF[i]) {
02302          PRT("// Hook for crypto factory "<<CryptMod[i]<<" undefined");
02303          continue;
02304       }
02305       //
02306       // Generate reference cipher
02307       RefCip[i] = CF[i]->Cipher(0,0,0);
02308       if (!RefCip[i]) continue;
02309       //
02310       // Count success
02311       ncf++;
02312    }
02313 
02314    // We are done
02315    return ncf;
02316 }
02317 
02318 int LocateFactoryIndex(char *tag, int &id)
02319 {
02320    // Searches tag for "_<id>" final strings
02321    // Extracts id and locate position in crypto array
02322 
02323    //
02324    // Locate factory ID
02325    XrdOucString sid(tag);
02326    sid.erase(0,sid.rfind('_')+1);
02327    id = atoi(sid.c_str());
02328    int j = ncrypt - 1;
02329    while (j >= 0) {
02330       if (CF[j] && CF[j]->ID() == id) break;
02331       j--;
02332    }
02333    if (j < 0)
02334       PRT("// warning: factory with ID "<< id << " not found");
02335 
02336    return j;
02337 }
02338 
02339 bool ExpPuk(const char *puk, bool read)
02340 {
02341    // Export public part of key contained in file 'puk'. The file
02342    // name can be absolute or relative to the standard 'genpuk' or
02343    // a date to be looked for in the genpuk directory. The public
02344    // key is exported in a file adding the extension ".export"
02345    // to 'puk'. If the file name is not defined the most recent
02346    // key in the standard genpuk directory is exported.
02347    // Return 0 in case of failure, 1 in case of success.
02348 
02349    // Read the keys in, if needed
02350    if (read) {
02351       // Standard genpuk dir
02352       XrdOucString genpukdir = Dir;
02353       genpukdir += GenPukRef;
02354 
02355       // Locate the file with the full key
02356       if (puk && strlen(puk) > 0) {
02357          // If not absolute, expand with respect to the standard genpuk dir
02358          if (puk[0] != '/')
02359             PukFile = genpukdir;
02360          PukFile += puk;
02361       } else {
02362          // Scan the standard genpuk to find the most recent key
02363          DIR *dir = opendir(genpukdir.c_str());
02364          if (!dir) {
02365             PRT("ExpPuk: cannot open standard genpuk dir "<<genpukdir);
02366             return 0;
02367          }
02368          dirent *ent = 0;
02369          time_t latest = -1;
02370          while ((ent = readdir(dir))) {
02371             // Skip non-key files
02372             if (strncmp(ent->d_name, "puk.", 4))
02373                continue;
02374             // Get the modification date
02375             XrdOucString fn = genpukdir;
02376             fn += ent->d_name;
02377             struct stat st;
02378             if (stat(fn.c_str(), &st) != 0) {
02379                PRT("ExpPuk: cannot stat "<<fn<<" - skipping");
02380                continue;
02381             }
02382             if (st.st_mtime > latest) {
02383                PukFile = fn;
02384                latest = st.st_mtime;
02385             }
02386          }
02387       }
02388 
02389       // Read the keys in
02390       if (!ReadPuk()) {
02391          PRT("ExpPuk: problem reading the key in");
02392          return 0;
02393       }
02394    }
02395 
02396    // Build the export file name
02397    XrdOucString expfile = PukFile;
02398    expfile += ".export";
02399    PRT("ExpPuk: exporting key from file "<<PukFile);
02400 
02401    // Now we save the public part in the export files
02402    // Open file, truncating if it exists already
02403    int fd = open(expfile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
02404    if (fd < 0) {
02405       PRT("ExpPuk: could not open/create file: "<<expfile.c_str());
02406       PRT("ExpPuk: errno: "<<errno);
02407       return 0;
02408    }
02409    //
02410    // Generate buffer
02411    XrdOucString buf;
02412    buf.assign("\n",0);
02413    buf += "********* Server PUK information **************\n\n";
02414    int i = 0;
02415    for (; i < ncrypt; i++) {
02416       XrdOucString ptag = SrvName + ":";
02417       ptag += SrvID; ptag += "_"; ptag += CF[i]->ID();
02418       buf += "puk:      "; buf += ptag; buf += "\n";
02419       int lpub = 0;
02420       char *pub = RefCip[i]->Public(lpub);
02421       if (pub) {
02422          buf += pub; buf += "\n";
02423          delete[] pub;
02424       }
02425       buf += "epuk\n";
02426    }
02427    buf += "\n";
02428    buf += "*********************************************";
02429    //
02430    // Write it to file
02431       // Now write the buffer to the stream
02432    while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
02433       errno = 0;
02434    //
02435    // Close file
02436    close (fd);
02437 
02438    // We are done
02439    return 1;
02440 }

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