XRootD
XrdSecpwdSrvAdmin.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c p w d S r v A d m i n . c c */
4 /* */
5 /* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Gerri Ganis for CERN */
7 /* */
8 /* This file is part of the XRootD software suite. */
9 /* */
10 /* XRootD is free software: you can redistribute it and/or modify it under */
11 /* the terms of the GNU Lesser General Public License as published by the */
12 /* Free Software Foundation, either version 3 of the License, or (at your */
13 /* option) any later version. */
14 /* */
15 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
16 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
17 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
18 /* License for more details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General Public License */
21 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
22 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
23 /* */
24 /* The copyright holder's institutional names and contributor's names may not */
25 /* be used to endorse or promote products derived from this software without */
26 /* specific prior written permission of the institution or contributor. */
27 /******************************************************************************/
28 
29 
30 // ---------------------------------------------------------------------- //
31 // //
32 // Password file administration //
33 // //
34 // Use this application to: //
35 // //
36 // - Create / Modify a password file for servers under your //
37 // administration. //
38 // Default location and name $(HOME)/.xrd/pwdadmin] //
39 // //
40 // XrdSecpwdSrvAdmin [<file>] //
41 // //
42 // NB: permissions must be such that the file is //
43 // readable and writable by owner only, e.g. 0600 //
44 // //
45 // //
46 // - Create / Modify a password file for servers enabled to verify //
47 // user passwords [default location and name $(HOME)/.xrd/pwduser] //
48 // //
49 // XrdSecpwdSrvAdmin -m user [<file>] //
50 // //
51 // NB: copy the file on the server machine if you are producing //
52 // it elsewhere; permissions must be such that the file is //
53 // writable by owner only, e.g. 0644 //
54 // //
55 // //
56 // - Create / Modify a autologin file //
57 // [default location and name $(HOME)/.xrd/pwdnetrc] //
58 // //
59 // XrdSecpwdSrvAdmin -m netrc [<file>] //
60 // //
61 // NB: permissions must be such that the file is //
62 // readable and writable by owner only, e.g. 0600 //
63 // //
64 // - Create / Modify the file with server public cipher initiators //
65 // [default location and name $(HOME)/.xrd/pwdsrvpuk] //
66 // //
67 // XrdSecpwdSrvAdmin -m srvpuk [<file>] //
68 // //
69 // NB: permissions must be such that the file is //
70 // writable by owner only, e.g. 0644 //
71 // //
72 // //
73 // Author: G.Ganis, 2005 //
74 // ---------------------------------------------------------------------- //
75 #include <cstdio>
76 #include <cstring>
77 #include <cstdlib>
78 #include <sys/types.h>
79 #include <sys/stat.h>
80 #include <unistd.h>
81 #include <sys/types.h>
82 #include <fcntl.h>
83 #include <cerrno>
84 #include <pwd.h>
85 #include <dirent.h>
86 
87 #include "XrdOuc/XrdOucString.hh"
88 
89 #include "XrdSut/XrdSutAux.hh"
90 #include "XrdSut/XrdSutPFEntry.hh"
91 #include "XrdSut/XrdSutPFile.hh"
92 #include "XrdSut/XrdSutRndm.hh"
93 
96 
97 //
98 // enum
99 enum kModes {
100  kM_undef = 0,
101  kM_admin = 1,
105  kM_help
106 };
107 const char *gModesStr[] = {
108  "kM_undef",
109  "kM_admin",
110  "kM_user",
111  "kM_netrc",
112  "kM_srvpuk",
113  "kM_help"
114 };
115 enum kActions {
116  kA_undef = 0,
117  kA_add = 1,
124  kA_browse
125 };
126 const char *gActionsStr[] = {
127  "kA_undef",
128  "kA_add",
129  "kA_update",
130  "kA_read",
131  "kA_remove",
132  "kA_disable",
133  "kA_copy",
134  "kA_trim",
135  "kA_browse"
136 };
137 
138 //
139 // Globals
140 int DebugON = 1;
141 XrdOucString DirRef = "~/.xrd/";
142 XrdOucString AdminRef = "pwdadmin";
143 XrdOucString UserRef = "pwduser";
144 XrdOucString NetRcRef = "pwdnetrc";
145 XrdOucString SrvPukRef= "pwdsrvpuk";
148 XrdOucString IDTag = "+++SrvID";
149 XrdOucString EmailTag = "+++SrvEmail";
150 XrdOucString HostTag = "+++SrvHost";
151 XrdOucString PukTag = "+++SrvPuk";
153 XrdOucString PukFile = "/home/ganis/.xrd/genpuk/puk.07May2005-0849";
156 int NoBackup = 1;
166 bool Backup = 1;
167 bool DontAsk = 0;
168 bool Force = 0;
169 bool Passwd = 1;
170 bool Change = 1;
171 bool Random = 0;
172 bool SavePw = 1;
173 bool SetID = 0;
174 bool SetEmail = 0;
175 bool SetHost = 0;
176 bool Create = 0;
177 bool Confirm = 1;
178 bool Import = 0;
179 bool Hash = 1;
180 bool ChangePuk = 0;
181 bool ChangePwd = 0;
182 bool ExportPuk = 0;
183 
184 #define NCRYPTMAX 10 // max number of crypto factories
185 
188 int ncrypt = 0; // number of available crypto factories
189 XrdOucString CryptMod[NCRYPTMAX] = {""}; // .. and their names
190 XrdCryptoCipher **RefCip = 0; // .. and their ciphers
194 
195 void Menu(int opt = 0);
196 int ParseArguments(int argc, char **argv);
197 void ParseCrypto();
198 bool CheckOption(XrdOucString opt, const char *ref, int &ival);
199 bool AddPassword(XrdSutPFEntry &ent, XrdOucString salt,
200  XrdOucString &ranpwd,
201  bool random, bool checkpw, bool &newpw);
202 bool AddPassword(XrdSutPFEntry &ent, bool &newpw, const char *pwd = 0);
203 void SavePasswd(XrdOucString tag, XrdOucString pwd, bool onetime);
204 bool ReadPasswd(XrdOucString &tag, XrdOucString &pwd, int &st);
205 bool ReadPuk(int &npuk, XrdOucString *tpuk, XrdOucString *puk);
206 int GeneratePuk();
207 bool SavePuk();
208 bool ReadPuk();
209 bool ExpPuk(const char *puk = 0, bool read = 1);
210 bool GetEntry(XrdSutPFile *ff, XrdOucString tag,
211  XrdSutPFEntry &ent, bool &check);
212 bool AskConfirm(const char *msg1, bool defact, const char *msg2 = 0);
213 int LocateFactoryIndex(char *tag, int &id);
214 
215 #define PRT(x) {std::cerr <<x <<std::endl;}
216 // Max number of attemps entreing a password
217 #define kMAXPWDATT 3
218 
219 #define kMAXPUK 5
222 
223 int main( int argc, char **argv )
224 {
225  // Application for password file administration
226 
227 
228  XrdSutPFEntry ent;
229  XrdSutPFEntry *nent = 0;
230  XrdOucString ans = "";
231  XrdOucString email = "";
232  XrdOucString uniqueid = "";
233  XrdOucString tag = "";
234  XrdOucString prompt = "Password: ";
235  XrdOucString ranpwd = "";
236  XrdOucString ImpPwd = "";
237  XrdOucString salt = "";
238  const char *pwdimp = 0;
239  bool checkpwd = 0;
240  bool newpw = 1;
241  bool check = 0;
242  int nr = 0, nm = 0;
243  int i = 0;
244  int entst = 0;
245 
246  // Parse arguments
247  if (ParseArguments(argc,argv)) {
248  exit(0);
249  }
250  ParseCrypto();
251 
252  // Set trace options
254 
255  // Attach to file
256  kXR_int32 openmode = (Create) ? kPFEcreate : 0;
257  XrdSutPFile ff(File.c_str(), openmode);
258  if (!ff.IsValid() && ff.LastError() == kPFErrNoFile) {
259  prompt = "Create file ";
260  prompt += File;
261  if (DontAsk || AskConfirm(prompt.c_str(),0)) {
262  if (Mode == kM_user || Mode == kM_srvpuk)
263  ff.Init(File.c_str(), kPFEcreate, 0644);
264  else
265  ff.Init(File.c_str(), kPFEcreate);
266  }
267  if (!ff.IsValid())
268  exit(1);
269  if (Mode == kM_admin || Mode == kM_user) {
270  if (SrvID.length() <= 0) {
271  if (!DontAsk && AskConfirm("Would you like to enter a server ID? ",1)) {
272  XrdSutGetLine(SrvID,"Enter ID (max 32 chars): ");
273  if (SrvID.length() > 32)
274  SrvID.erase(32);
275  } else {
276  PRT("Server ID will be generated randomly. It can be changed");
277  PRT("at any time with 'add -srvID <ID>'.");
278  //
279  // Set random ID
282  //
283  // Add local user name
284  struct passwd *pw = getpwuid(getuid());
285  if (pw) {
286  SrvID.insert(':',0);
287  SrvID.insert(pw->pw_name,0);
288  }
289  }
290  } else if (DontAsk) {
291  // This is a force creation where no prompt request can be answered
292  SetID = 0;
293  }
294  PRT("Server ID: " << SrvID);
295  if (SrvID.length() > 0) {
296  //
297  // Fill entry
298  ent.SetName(IDTag.c_str());
299  ent.status = kPFE_special;
300  ent.cnt = 1;
301  ent.buf1.SetBuf(SrvID.c_str(),SrvID.length()+1);
302  //
303  // Write entry
304  ent.mtime = time(0);
305  ff.WriteEntry(ent);
306  PRT(" File successfully created with server ID set to: "
307  <<SrvID.c_str());
308  }
309  // Generate srvpuk for admin
310  if (Mode == kM_admin) {
311 
312  int ncf = GeneratePuk();
313  if (ncf != ncrypt)
314  PRT("// Could generate ref ciphers for all the factories");
315 
316  // Update file
317  for ( i = 0; i < ncrypt; i++ ) {
318  if (RefCip[i]) {
319  //
320  // Build tag
321  tag = PukTag + '_';
322  tag += CF[i]->ID();
323  //
324  // Serialize in a buffer
325  XrdSutBucket *bck = RefCip[i]->AsBucket();
326  if (bck) {
327  //
328  // Prepare Entry
329  ent.SetName(tag.c_str());
330  ent.status = kPFE_special;
331  ent.cnt = 2; // protected
332  ent.buf1.SetBuf(bck->buffer,bck->size);
333  //
334  // Write entry
335  ent.mtime = time(0);
336  ff.WriteEntry(ent);
337  PRT(" Server Puk saved for crypto: "<<CF[i]->Name());
338  delete bck;
339  bck = 0;
340  }
341  }
342  }
343  //
344  // Backup also on separate file
345  if (!SavePuk()) {
346  PRT("// Problems with puk backup ");
347  }
348  }
349  } else {
350  PRT(" File successfully created ");
351  }
352  }
353 
354  // If admin, check for special entries
355  // (Server Unique ID, Email, Host name)
356  if (Mode == kM_admin) {
357  //
358  // Ref ciphers
359  ent.Reset();
360  nm = ff.SearchEntries(PukTag.c_str(),0);
361  if (nm) {
362  int *ofs = new int[nm];
363  ff.SearchEntries(PukTag.c_str(),0,ofs,nm);
364  for ( i = 0; i < nm ; i++) {
365  nr = ff.ReadEntry(ofs[i],ent);
366  if (nr > 0) {
367  XrdSutBucket bck;
368  bck.SetBuf(ent.buf1.buf,ent.buf1.len);
369  // Locate factory ID
370  int id = 0;
371  int ii = LocateFactoryIndex(ent.name, id);
372  if (ii < 0) {
373  PRT("// Factory ID not found: corruption ?");
374  exit(1);
375  }
376  if (!(RefCip[i] = CF[ii]->Cipher(&bck))) {
377  PRT("// Could not instantiate cipher for factory "<<CF[ii]->Name());
378  exit(1);
379  }
380  }
381  }
382  } else {
383  PRT("// Ref puk ciphers not found: corruption ?");
384  exit(1);
385  }
386 
387 
388  if (ff.ReadEntry(IDTag.c_str(),ent) <= 0 && !SetID) {
389  PRT(" Unique ID missing: 'add -srvID' to set it");
390  } else if (!SetID) {
391  SrvID.insert(ent.buf1.buf,0,ent.buf1.len);
392  }
393  //
394  // Unique ID
395  ent.Reset();
396  if (ff.ReadEntry(IDTag.c_str(),ent) <= 0 && !SetID) {
397  PRT(" Unique ID missing: 'add -srvID' to set it");
398  } else if (!SetID) {
399  SrvID.insert(ent.buf1.buf,0,ent.buf1.len);
400  }
401  //
402  // Email
403  ent.Reset();
404  if (ff.ReadEntry(EmailTag.c_str(),ent) <= 0 && !SetEmail) {
405  PRT(" Contact E-mail not set: 'add -email <email>' to set it");
406  } else if (!SetEmail) {
407  Email.insert(ent.buf1.buf,0,ent.buf1.len);
408  }
409  //
410  // Server Host name
411  ent.Reset();
412  if (ff.ReadEntry(HostTag.c_str(),ent) <= 0 && !SetHost) {
413  PRT(" Local host name not set: 'add -host <host>' to set it");
414  } else if (!SetHost) {
415  SrvName.insert(ent.buf1.buf,0,ent.buf1.len);
416  }
417  }
418 
419  switch (Action) {
420  case kA_update:
421  // Like 'add', forcing write
422  case kA_add:
423  if (Action == kA_update) Force = 1;
424  //
425  // Add / Update entry
426  //
427  // If admin, check first if we are required to update/create
428  // some special entry (Server Unique ID, Email, Host Name)
429  if (Mode == kM_admin) {
430  //
431  // Export current Server PUK
432  if (ExportPuk) {
433  if (!ExpPuk()) {
434  PRT("// Could not export public keys");
435  }
436  //
437  // We are done
438  break;
439  }
440  //
441  // Server PUK
442  ent.Reset();
443  if (ChangePuk) {
444  if (!DontAsk && !AskConfirm("Override server PUK?",0,0))
445  break;
446  //
447  // If we are given a file name, try import from the file
448  if (Import && PukFile.length() > 0) {
449  if (!ReadPuk()) {
450  PRT("// Problem importing puks from "<<PukFile<<
451  " - exit ");
452  break;
453  }
454  } else {
455  // Generate new puks
456  if (GeneratePuk() != ncrypt) {
457  PRT("// Could not generate ref ciphers for all the factories");
458  break;
459  }
460  }
461  //
462  // Backup also on separate file
463  if (!SavePuk()) {
464  PRT("// Problems with puk backup ");
465  }
466  //
467  // Now shift up the old one(s)
468  nm = ff.SearchEntries(PukTag.c_str(),0);
469  if (nm) {
470  PRT("// Found "<<nm<<" entries for tag '"<<PukTag.c_str()<<
471  "' in file: "<<ff.Name());
472  //
473  // Book vector for offsets
474  int *ofs = new int[nm];
475  //
476  // Get number of entries related
477  ff.SearchEntries(PukTag.c_str(),0,ofs,nm);
478  //
479  // Read entries now
480  for ( i = 0; i < nm ; i++) {
481  nr = ff.ReadEntry(ofs[i],ent);
482  if (nr > 0) {
483  //
484  // Locate factory ID
485  int id;
486  int j = LocateFactoryIndex(ent.name,id);
487  if (j < 0) break;
488  // Serialize in a buffer
489  XrdSutBucket *bck = RefCip[j]->AsBucket();
490  if (bck) {
491  // Shift up buffer content (buf 4 is removed)
492  if (ent.buf4.buf)
493  delete[] ent.buf4.buf;
494  ent.buf4.buf = ent.buf3.buf;
495  ent.buf4.len = ent.buf3.len;
496  ent.buf3.buf = ent.buf2.buf;
497  ent.buf3.len = ent.buf2.len;
498  ent.buf2.buf = ent.buf1.buf;
499  ent.buf2.len = ent.buf1.len;
500  // fill buf 1 with new puk
501  ent.buf1.SetBuf(bck->buffer,bck->size);
502  //
503  // Write entry
504  ent.mtime = time(0);
505  ff.WriteEntry(ent);
506  PRT(" Server Puk updated for crypto: "<<CF[i]->Name());
507  delete bck;
508  bck = 0;
509  }
510  //
511  // Flag user entries
512  char stag[4];
513  sprintf(stag,"*_%d",id);
514  int nofs = ff.SearchEntries(stag,2);
515  if (nofs > 0) {
516  int *uofs = new int[nofs];
517  ff.SearchEntries(stag,2,uofs,nofs);
518  XrdSutPFEntry uent;
519  int k = 0, nnr = 0;
520  for (; k < nofs; k++) {
521  uent.Reset();
522  nnr = ff.ReadEntry(uofs[k],uent);
523  if (nnr > 0 && !strstr(uent.name,PukTag.c_str())) {
524  char c = 0;
525  if (uent.buf4.buf) {
526  c = *(uent.buf4.buf);
527  c++;
528  if (c > 4)
529  c = 1;
530  *(uent.buf4.buf) = c;
531  } else {
532  uent.buf4.buf = new char[1];
533  uent.buf4.len = 1;
534  *(uent.buf4.buf) = 2;
535  }
536  // Write entry
537  uent.mtime = time(0);
538  ff.WriteEntry(uent);
539  }
540  }
541  }
542  } else {
543  PRT("// warning: problems reading entry: corruption?");
544  break;
545  }
546  }
547  } else {
548  PRT("// WARNING: No entry for tag '"<<PukTag.c_str()<<
549  "' found in file: "<<ff.Name()<<" : corruption? ");
550  break;
551  }
552  }
553  //
554  // Server Unique ID
555  ent.Reset();
556  if (SetID) {
557  if (!GetEntry(&ff,IDTag,ent,check)) {
558  if (!check || AskConfirm("Override server ID?",0,
559  "This may cause inconveniences"
560  " to clients")) {
561  //
562  // Prepare Entry
563  ent.SetName(IDTag.c_str());
564  ent.status = kPFE_special;
565  ent.cnt = 1;
566  ent.buf1.SetBuf(SrvID.c_str(),SrvID.length()+1);
567  //
568  // Write entry
569  ent.mtime = time(0);
570  ff.WriteEntry(ent);
571  PRT(" Server ID set to: "<<SrvID.c_str());
572  }
573  }
574  }
575  //
576  // Email
577  ent.Reset();
578  if (SetEmail) {
579  if (!GetEntry(&ff,EmailTag,ent,check)) {
580  if (!check || AskConfirm("Override contact e-mail"
581  " address?",0)) {
582  //
583  // Prepare Entry
584  ent.SetName(EmailTag.c_str());
585  ent.status = kPFE_special;
586  ent.cnt = 1;
587  ent.buf1.SetBuf(Email.c_str(),Email.length()+1);
588  //
589  // Write entry
590  ent.mtime = time(0);
591  ff.WriteEntry(ent);
592  PRT(" Contact e-mail set to: "<<Email.c_str());
593  }
594  }
595  }
596  //
597  // Server host name
598  ent.Reset();
599  if (SetHost) {
600  if (!GetEntry(&ff,HostTag,ent,check)) {
601  if (!check || AskConfirm("Override server host name?",0)) {
602  //
603  // Prepare Entry
604  ent.SetName(HostTag.c_str());
605  ent.status = kPFE_special;
606  ent.cnt = 1;
607  ent.buf1.SetBuf(SrvName.c_str(),SrvName.length()+1);
608  //
609  // Write entry
610  ent.mtime = time(0);
611  ff.WriteEntry(ent);
612  PRT(" Server host name set to: "<<SrvName.c_str());
613  }
614  }
615  }
616 
617  }
618  //
619  // If import mode for read info from file
620  if (Mode == kM_srvpuk) {
621  if (!Import) {
622  PRT("// Updating the server puk file requires a file with "<<
623  "the keys received by the server administrator:");
624  PRT("// rerun with option '-import <file_with_keys>' ");
625  break;
626  }
628  break;
629  //
630  // Now we loop over tags
631  for (i = 0; i < nHostPuk; i++) {
632  // Check if not already existing
633  ent.Reset();
634  if (GetEntry(&ff,TagHostPuk[i],ent,check)) {
635  break;
636  }
637  // Fill in new puk
638  ent.buf1.SetBuf(HostPuk[i].c_str(),HostPuk[i].length()+1);
639  // Write entry
640  ent.mtime = time(0);
641  ff.WriteEntry(ent);
642  if (check) {
643  PRT("// Server puk "<<TagHostPuk[i]<<" updated");
644  } else {
645  PRT("// Server puk "<<TagHostPuk[i]<<" added");
646  }
647  }
648  //
649  // Browse new content
650  ff.Browse();
651  //
652  // We are done
653  break;
654  }
655  //
656  // If import mode for read info from file
657  if (Mode == kM_netrc) {
658  if (Import) {
659  if (!ReadPasswd(NameTag,ImpPwd,entst))
660  break;
661  pwdimp = ImpPwd.c_str();;
662  }
663  // Special treatment for non-hashed passwords (provided
664  // to allow store info for crypt-like credentials)
665  if (!Hash) {
666  // Check if not already existing
667  ent.Reset();
668  if (GetEntry(&ff,NameTag,ent,checkpwd)) {
669  break;
670  }
671  // Reset status and cnt
672  ent.status = entst;
673  ent.cnt = 0;
674  //
675  // Fill with password
676  if (!AddPassword(ent, newpw, pwdimp)) {
677  PRT("Error creating new password: "<<gModesStr[Mode]);
678  break;
679  }
680  //
681  // Save (or update) entry
682  ent.mtime = time(0);
683  ff.WriteEntry(ent);
684  PRT(" Entry for tag '"<<NameTag<<
685  "' created / updated");
686  // We are done
687  break;
688  }
689  }
690  //
691  // Now we need a name tag
692  if (!NameTag.length()) break;
693  //
694  // Ask confirmation, if required
695  prompt = "Adding/Updating entry for tag: ";
696  prompt += NameTag;
697  if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
698  break;
699  //
700  // Normal operations
701  KDFun = 0;
702  KDFunLen = 0;
703  newpw = 1;
704  //
705  // New salt (random machinery init only once)
706  if (Mode != kM_netrc) {
708  XrdSutRndm::GetString(3,8,salt);
709  if (IterNum.length() > 0) {
710  // Insert non default iteration number in salt
711  salt.insert(IterNum,0);
712  }
713  }
714  //
715  for ( i = 0; i < ncrypt; i++ ) {
716  // Get hook to crypto factory
718  if (!CF[i]) {
719  PRT("Hook for crypto factory undefined: "<<CryptMod[i].c_str());
720  break;
721  }
722  //
723  // Get one-way hash function
724  KDFun = CF[i]->KDFun();
725  KDFunLen = CF[i]->KDFunLen();
726  if (!KDFun || !KDFunLen) {
727  PRT("Error resolving one-way hash functions ");
728  break;
729  }
730  //
731  // Build tag
732  tag = NameTag + '_';
733  tag += CF[i]->ID();
734  // Check if not already existing
735  ent.Reset();
736  if (GetEntry(&ff,tag,ent,checkpwd)) {
737  break;
738  }
739  if (Mode == kM_netrc) {
740  // If just a request for password change not much to do
741  if (ChangePwd) {
742  if (!checkpwd)
743  break;
744  else
745  // Update the status
746  ent.status = kPFE_onetime;
747  } else {
748  // Reset status and cnt
749  if (pwdimp)
750  ent.status = entst;
751  else
752  ent.status = kPFE_ok;
753  ent.cnt = 0;
754  //
755  // Fill with password
756  if (!AddPassword(ent, newpw, pwdimp)) {
757  PRT("Error creating new password: "<<gModesStr[Mode]);
758  break;
759  }
760  }
761  } else {
762  // Reset cnt
763  ent.cnt = 0;
764  if (Passwd) {
765  // Set status
766  ent.status = Change ? kPFE_onetime : kPFE_ok;
767  //
768  // Fill with password
769  if (!AddPassword(ent, salt, ranpwd, Random, checkpwd, newpw)) {
770  PRT("Error creating new password: "<<gModesStr[Mode]);
771  break;
772  }
773  } else {
774  ent.buf1.SetBuf();
775  ent.buf2.SetBuf();
776  ent.buf3.SetBuf();
777  ent.buf4.SetBuf();
778  // Just enable entry
779  ent.status = kPFE_allowed;
780  }
781  }
782  //
783  // Save (or update) entry
784  ent.mtime = time(0);
785  ff.WriteEntry(ent);
786  PRT(" Entry for tag '"<<tag.c_str()<<
787  "' created / updated");
788  }
789  //
790  // Save password, if requested
791  if (SavePw)
792  SavePasswd(NameTag, ranpwd, Change);
793 
794  // Browse the new status
795  ff.Browse();
796  break;
797 
798  case kA_read:
799  //
800  // Get number of entries related
801  nm = ff.SearchEntries(NameTag.c_str(),0);
802  PRT("//-----------------------------------------------------"
803  "--------------------//");
804  PRT("//");
805  if (nm) {
806  PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
807  "' in file: "<<ff.Name());
808  //
809  // Book vector for offsets
810  int *ofs = new int[nm];
811  //
812  // Get number of entries related
813  ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
814  //
815  // Read entries now
816  for ( i = 0; i < nm ; i++) {
817  nr = ff.ReadEntry(ofs[i],ent);
818  if (nr > 0) {
819  PRT("// #:"<<i+1<<" "<<ent.AsString());
820  } else {
821  PRT("// Entry for ofs "<<ofs[i]<<
822  " not found in file: "<<ff.Name());
823  }
824  }
825  } else {
826  PRT("// No entry for tag '"<<NameTag.c_str()<<
827  "' found in file: "<<ff.Name());
828  }
829  PRT("//");
830  PRT("//-----------------------------------------------------"
831  "--------------------//");
832  break;
833 
834  case kA_remove:
835  //
836  // Ask confirmation, if required
837  prompt = "Removing entry for tag: ";
838  prompt += NameTag;
839  if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
840  break;
841  //
842  // Get number of entries related
843  nm = ff.SearchEntries(NameTag.c_str(),0);
844  PRT("//-----------------------------------------------------"
845  "--------------------//");
846  PRT("//");
847  if (nm) {
848  PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
849  "' in file: "<<ff.Name());
850  //
851  // Book vector for offsets
852  int *ofs = new int[nm];
853  //
854  // Get number of entries related
855  ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
856  //
857  // Read entries now
858  for ( i = 0; i < nm ; i++) {
859  if (ff.RemoveEntry(ofs[i]) == 0) {
860  PRT("// Entry for tag '"<<NameTag.c_str()<<
861  "' removed from file: "<<ff.Name());
862  } else {
863  PRT("// Entry for tag '"<<NameTag.c_str()<<
864  "' not found in file: "<<ff.Name());
865  }
866  }
867  } else {
868  PRT("// No entry for tag '"<<NameTag.c_str()<<
869  "' found in file: "<<ff.Name());
870  }
871  PRT("//");
872  PRT("//-----------------------------------------------------"
873  "--------------------//");
874  break;
875 
876  case kA_disable:
877  //
878  // Ask confirmation, if required
879  prompt = "Disabling entry for tag: ";
880  prompt += NameTag;
881  if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
882  break;
883  //
884  // Get number of entries related
885  nm = ff.SearchEntries(NameTag.c_str(),0);
886  PRT("//-----------------------------------------------------"
887  "--------------------//");
888  PRT("//");
889  if (nm) {
890  PRT("// Found "<<nm<<" entries for tag '"<<NameTag.c_str()<<
891  "' in file: "<<ff.Name());
892  //
893  // Book vector for offsets
894  int *ofs = new int[nm];
895  //
896  // Get number of entries related
897  ff.SearchEntries(NameTag.c_str(),0,ofs,nm);
898  //
899  // Read entries now
900  for ( i = 0; i < nm ; i++) {
901  nr = ff.ReadEntry(ofs[i],ent);
902  if (nr > 0) {
903  // Disable entry
904  ent.status = kPFE_disabled;
905  ent.cnt = 0;
906  ent.buf1.SetBuf();
907  ent.buf2.SetBuf();
908  ent.buf3.SetBuf();
909  ent.buf4.SetBuf();
910  // Save (or update) entry
911  ent.mtime = time(0);
912  ff.WriteEntry(ent);
913  PRT("// Entry for tag '"<<ent.name<<
914  "' disabled");
915  } else {
916  PRT("// Entry for ofs "<<ofs[i]<<
917  " not found in file: "<<ff.Name());
918  }
919  }
920  } else {
921  PRT("// No entry for tag '"<<NameTag.c_str()<<
922  "' found in file: "<<ff.Name());
923  }
924  PRT("//");
925  PRT("//-----------------------------------------------------"
926  "--------------------//");
927  break;
928 
929  case kA_copy:
930  //
931  // Ask confirmation, if required
932  prompt = "Copying entry for tag: ";
933  prompt += NameTag;
934  prompt += " into tag: ";
935  prompt += CopyTag;
936  if (!DontAsk && !AskConfirm("Do you want to continue?",0,prompt.c_str()))
937  break;
938  //
939  // Ready entry
940  if (ff.ReadEntry(NameTag.c_str(),ent) <= 0) {
941  PRT("Entry to copy not found missing");
942  break;
943  }
944  //
945  // Prepare New Entry
946  nent = new XrdSutPFEntry(ent);
947  PRT("//-----------------------------------------------------"
948  "--------------------//");
949  PRT("//");
950  if (nent) {
951  nent->SetName(CopyTag.c_str());
952  //
953  // Write entry
954  nent->mtime = time(0);
955  ff.WriteEntry(*nent);
956  PRT("// Entry for tag '"<<nent->name<<
957  "' created");
958  delete nent;
959  } else {
960  PRT("// Cannot create new entry: out of memory");
961  break;
962  }
963  PRT("//");
964  PRT("//-----------------------------------------------------"
965  "--------------------//");
966  break;
967 
968  case kA_trim:
969  case kA_browse:
970  default:
971  //
972  // Trim the file first before browsing
973  if (Action == kA_trim) ff.Trim();
974  //
975  // Browse
976  ff.Browse();
977  break;
978  }
979 
980  exit(0);
981 }
982 
983 
984 void Menu(int opt)
985 {
986  // Print the menu
987  // Options: 0 intro w/ head/tail
988  // 1 intro w/o head/tail
989  // 2 keywords
990 
991  // Head
992  if (opt == 0) {
993  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
994  PRT("+ +");
995  PRT("+ x r d p w d a d m i n +");
996  PRT("+ +");
997  PRT("+ Administration of pwd files +");
998  }
999 
1000  // Intro
1001  if (opt <= 1) {
1002  PRT("+ +");
1003  PRT("+ Syntax: +");
1004  PRT("+ +");
1005  PRT("+ xrdpwdadmin [-h] [-m <mode>] [options] +");
1006  PRT("+ +");
1007  PRT("+ -h display this menu +");
1008  PRT("+ +");
1009  PRT("+ -m choose mode (admin, user, netrc, srvpuk) [admin] +");
1010  PRT("+ +");
1011  PRT("+ admin: +");
1012  PRT("+ create / modify the main file used by servers +");
1013  PRT("+ started from this account to validate clients +");
1014  PRT("+ credentials. Default location and name: +");
1015  PRT("+ $(HOME)/.xrd/pwdadmin +");
1016  PRT("+ +");
1017  PRT("+ NB: file must readable and writable by owner +");
1018  PRT("+ only e.g. 0600 +");
1019  PRT("+ +");
1020  PRT("+ user: +");
1021  PRT("+ create / modify local file used by servers +");
1022  PRT("+ to validate this user credentials. +");
1023  PRT("+ Default location and name: +");
1024  PRT("+ $(HOME)/.xrd/pwduser +");
1025  PRT("+ +");
1026  PRT("+ NB: the file must be copied on the server machine +");
1027  PRT("+ if produced elsewhere; file must be writable +");
1028  PRT("+ by the owner only, e.g. 0644 +");
1029  PRT("+ +");
1030  PRT("+ netrc: +");
1031  PRT("+ create / modify local autologin file +");
1032  PRT("+ Default location and name: +");
1033  PRT("+ $(HOME)/.xrd/pwdnetrc +");
1034  PRT("+ +");
1035  PRT("+ NB: file must readable and writable by owner +");
1036  PRT("+ only e.g. 0600 +");
1037  PRT("+ +");
1038  PRT("+ srvpuk: +");
1039  PRT("+ create / modify local file with known server +");
1040  PRT("+ public cipher initializers. +");
1041  PRT("+ Default location and name: +");
1042  PRT("+ $(HOME)/.xrd/pwdsrvpuk +");
1043  PRT("+ +");
1044  PRT("+ NB: file must be writable by the owner only +");
1045  PRT("+ e.g. 0644 +");
1046  }
1047 
1048  // Intro
1049  if (opt <= 2) {
1050  PRT("+ +");
1051  PRT("+ Options: +");
1052  PRT("+ +");
1053  PRT("+ add <name> [-[no]force] [-[no]random] [-[no]savepw] +");
1054  PRT("+ add entry with tag <name>; the application prompts +");
1055  PRT("+ for the password +");
1056  PRT("+ +");
1057  PRT("+ add <name> -import <pwd_file> +");
1058  PRT("+ add entry with tag <name> importing the pwd from +");
1059  PRT("+ the file send by the server administrator +");
1060  PRT("+ [netrc only] +");
1061  PRT("+ +");
1062  PRT("+ add -import <srvkey_file> +");
1063  PRT("+ add new server key importing the key from +");
1064  PRT("+ the file send by the server administrator +");
1065  PRT("+ [srvpuk only] +");
1066  PRT("+ +");
1067  PRT("+ update <name> [options] +");
1068  PRT("+ equivalent to 'add -force' +");
1069  PRT("+ +");
1070  PRT("+ read <name> +");
1071  PRT("+ list some information of entry associated with tag +");
1072  PRT("+ <name> (status, count, date of last change, buffer +");
1073  PRT("+ lengths); buffer contents not listed +");
1074  PRT("+ +");
1075  PRT("+ remove <name> +");
1076  PRT("+ Make entry associated with tag <name> inactive +");
1077  PRT("+ (Spce is recovered during next trim operation) +");
1078  PRT("+ +");
1079  PRT("+ copy <name> <newname> +");
1080  PRT("+ Create new entry with tag <newname> and content of +");
1081  PRT("+ existing entry with tag <name> +");
1082  PRT("+ +");
1083  PRT("+ trim [-nobackup] +");
1084  PRT("+ Trim the file content eliminating all the inactive +");
1085  PRT("+ entries; a backup is created in <file>.bak unless +");
1086  PRT("+ the option '-nobackup' is specified +");
1087  PRT("+ +");
1088  PRT("+ browse +");
1089  PRT("+ list a table about the file content +");
1090  }
1091 
1092  // Intro
1093  if (opt <= 3) {
1094  PRT("+ +");
1095  PRT("+ -dontask +");
1096  PRT("+ do not prompt for questions: when in doubt use +");
1097  PRT("+ defaults or fail +");
1098  PRT("+ [default: ask] +");
1099  PRT("+ -force +");
1100  PRT("+ overwrite entry if it exists already +");
1101  PRT("+ [default: do not overwrite] +");
1102  PRT("+ -[no]change +");
1103  PRT("+ do [not] require user to change info on first use +");
1104  PRT("+ [default: admin: change / user: no change +");
1105  PRT("+ -crypto [-]<crypt1>|[-]<crypt2>|... +");
1106  PRT("+ create information for the given crypto modules +");
1107  PRT("+ ('|' separated list) in addition to default ones +");
1108  PRT("+ (normally ssl and local); use '-' in front to avoid +");
1109  PRT("+ avoid creating a entry for a module; one entry is +");
1110  PRT("+ for each module with effective tag of the form +");
1111  PRT("+ name_<cryptoID> [default list: ssl] +");
1112  PRT("+ [default: create backup] +");
1113  }
1114 
1115  // Tail
1116  PRT("+ +");
1117  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1118 }
1119 
1120 int ParseArguments(int argc, char **argv)
1121 {
1122  // Parse application arguments filling relevant global variables
1123  bool changeset = 0;
1124  bool randomset = 0;
1125  bool savepwset = 0;
1126  bool randomid = 0;
1127 
1128  // Number of arguments
1129  if (argc < 0 || !argv[0]) {
1130  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1131  PRT("+ Insufficient number or arguments! +");
1132  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1133  // Print main menu
1134  Menu(0);
1135  return 1;
1136  }
1137  --argc;
1138  ++argv;
1139 
1140  //
1141  // Loop over arguments
1142  while ((argc >= 0) && (*argv)) {
1143 
1144  XrdOucString opt = "";
1145  int ival = -1;
1146  if(*(argv)[0] == '-') {
1147 
1148  opt = *argv;
1149  opt.erase("-");
1150  if (CheckOption(opt,"m",ival)) {
1151  if (Mode != kM_undef) {
1152  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1153  PRT("+ Only one valid '-m' option allowed: ignoring +");
1154  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1155  --argc;
1156  ++argv;
1157  if (argc >= 0 && (*argv && *(argv)[0] == '-')) {
1158  argc++;
1159  argv--;
1160  }
1161  }
1162  --argc;
1163  ++argv;
1164  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1165  XrdOucString mode = *argv;
1166  if (CheckOption(mode,"admin",ival)) {
1167  Mode = kM_admin;
1168  } else if (CheckOption(mode,"user",ival)) {
1169  Mode = kM_user;
1170  } else if (CheckOption(mode,"netrc",ival)) {
1171  Mode = kM_netrc;
1172  } else if (CheckOption(mode,"srvpuk",ival)) {
1173  Mode = kM_srvpuk;
1174  } else if (CheckOption(mode,"help",ival)) {
1175  Mode = kM_help;
1176  } else {
1177  PRT("++++++++++++++++++++++++++++++++++++++"
1178  "++++++++++++++++++++++");
1179  PRT("+ Ignoring unrecognized more: "<<mode.c_str());
1180  PRT("++++++++++++++++++++++++++++++++++++++"
1181  "++++++++++++++++++++++");
1182  }
1183  } else {
1184  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1185  PRT("+ Option '-m' requires {admin,user,netrc,srvpuk}: ignoring +");
1186  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1187  argc++;
1188  argv--;
1189  }
1190  } else if (CheckOption(opt,"h",ival) ||
1191  CheckOption(opt,"help",ival) ||
1192  CheckOption(opt,"menu",ival)) {
1193  Mode = kM_help;
1194  } else if (CheckOption(opt,"f",ival)) {
1195  --argc;
1196  ++argv;
1197  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1198  Path = *argv;
1199  } else {
1200  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1201  PRT("+ Option '-f' requires a file or directory name: ignoring +");
1202  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1203  argc++;
1204  argv--;
1205  }
1206  } else if (CheckOption(opt,"dontask",ival)) {
1207  DontAsk = ival;
1208  } else if (CheckOption(opt,"force",ival)) {
1209  Force = ival;
1210  } else if (CheckOption(opt,"change",ival)) {
1211  Change = ival;
1212  changeset = 1;
1213  } else if (CheckOption(opt,"passwd",ival)) {
1214  Passwd = ival;
1215  } else if (CheckOption(opt,"backup",ival)) {
1216  Backup = ival;
1217  } else if (CheckOption(opt,"random",ival)) {
1218  Random = ival;
1219  randomset = 1;
1220  } else if (CheckOption(opt,"savepw",ival)) {
1221  SavePw = ival;
1222  savepwset = 1;
1223  } else if (CheckOption(opt,"confirm",ival)) {
1224  Confirm = ival;
1225  } else if (CheckOption(opt,"create",ival)) {
1226  Create = ival;
1227  } else if (CheckOption(opt,"hash",ival)) {
1228  Hash = ival;
1229  } else if (CheckOption(opt,"changepuk",ival)) {
1230  ChangePuk = ival;
1231  } else if (CheckOption(opt,"changepwd",ival)) {
1232  ChangePwd = ival;
1233  } else if (CheckOption(opt,"exportpuk",ival)) {
1234  ExportPuk = ival;
1235  } else if (CheckOption(opt,"iternum",ival)) {
1236  --argc;
1237  ++argv;
1238  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1239  int iter = strtol(*argv,0,10);
1240  if (iter > 0 && errno != ERANGE) {
1241  IterNum = "$$";
1242  IterNum += *argv;
1243  IterNum += "$";
1244  } else {
1245  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1246  PRT("+ Option '-iternum' requires a positive number: ignoring +");
1247  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1248  argc++;
1249  argv--;
1250  }
1251  } else {
1252  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1253  PRT("+ Option '-iternum' requires a positive number: ignoring +");
1254  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1255  argc++;
1256  argv--;
1257  }
1258  } else if (CheckOption(opt,"crypto",ival)) {
1259  --argc;
1260  ++argv;
1261  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1262  CryptList = *argv;
1263  } else {
1264  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1265  PRT("+ Option '-crypto' requires a list of modules: ignoring +");
1266  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1267  argc++;
1268  argv--;
1269  }
1270  } else if (CheckOption(opt,"import",ival)) {
1271  --argc;
1272  ++argv;
1273  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1274  if (Mode == kM_netrc) {
1275  PwdFile = *argv;
1276  } else {
1277  PukFile = *argv;
1278  }
1279  Import = 1;
1280  } else {
1281  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1282  PRT("+ Option '-import' requires a file name: ignoring +");
1283  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1284  argc++;
1285  argv--;
1286  }
1287  } else if (CheckOption(opt,"srvID",ival)) {
1288  --argc;
1289  ++argv;
1290  SetID = 1;
1291  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1292  SrvID = *argv;
1293  } else {
1294  SrvID = "";
1295  randomid = 1;
1296  argc++;
1297  argv--;
1298  }
1299  } else if (CheckOption(opt,"email",ival)) {
1300  --argc;
1301  ++argv;
1302  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1303  Email = *argv;
1304  SetEmail = 1;
1305  } else {
1306  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1307  PRT("+ Option '-email' requires an email string: ignoring +");
1308  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1309  argc++;
1310  argv--;
1311  }
1312  } else if (CheckOption(opt,"host",ival)) {
1313  --argc;
1314  ++argv;
1315  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1316  SrvName = *argv;
1317  SetHost = 1;
1318  } else {
1319  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1320  PRT("+ Option '-host' requires the local host name: ignoring +");
1321  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1322  argc++;
1323  argv--;
1324  }
1325  } else {
1326  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1327  PRT("+ Ignoring unrecognized option: "<<*argv);
1328  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1329  }
1330 
1331  } else {
1332  //
1333  // Action keyword
1334  opt = *argv;
1335  int iad = -1, iup = -1, ird = -1, irm = -1, idi = -1, icp = -1;
1336  if (CheckOption(opt,"add",iad) || CheckOption(opt,"update",iup) ||
1337  CheckOption(opt,"read",ird) || CheckOption(opt,"remove",irm) ||
1338  CheckOption(opt,"disable",idi) || CheckOption(opt,"copy",icp)) {
1339  Action = (Action == kA_undef && iad == 1) ? kA_add : Action;
1340  Action = (Action == kA_undef && iup == 1) ? kA_update : Action;
1341  Action = (Action == kA_undef && ird == 1) ? kA_read : Action;
1342  Action = (Action == kA_undef && irm == 1) ? kA_remove : Action;
1343  Action = (Action == kA_undef && idi == 1) ? kA_disable : Action;
1344  Action = (Action == kA_undef && icp == 1) ? kA_copy : Action;
1345  --argc;
1346  ++argv;
1347  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1348  NameTag = *argv;
1349  if (icp == 1) {
1350  --argc;
1351  ++argv;
1352  if (argc >= 0 && (*argv && *(argv)[0] != '-')) {
1353  CopyTag = *argv;
1354  } else {
1355  PRT("+++++++++++++++++++++++++++++++++++++++++"
1356  "+++++++++++++++++++");
1357  PRT("+ 'copy': missing destination tag: ignoring"
1358  " +");
1359  PRT("+++++++++++++++++++++++++++++++++++++++++"
1360  "+++++++++++++++++++");
1361  CopyTag = "";
1362  argc++;
1363  argv--;
1364  }
1365  }
1366  } else {
1367  NameTag = "";
1368  argc++;
1369  argv--;
1370  }
1371  } else if (CheckOption(opt,"trim",ival)) {
1372  Action = kA_trim;
1373  } else if (CheckOption(opt,"browse",ival)) {
1374  Action = kA_browse;
1375  } else {
1376  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1377  PRT("+ Ignoring unrecognized keyword action: "<<opt.c_str());
1378  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1379  }
1380  }
1381  --argc;
1382  ++argv;
1383  }
1384 
1385  //
1386  // Default mode 'admin'
1387  Mode = (Mode == 0) ? kM_admin : Mode;
1388 
1389  //
1390  // If help mode, print menu and exit
1391  if (Mode == kM_help) {
1392  // Print main menu
1393  Menu(0);
1394  return 1;
1395  }
1396 
1397  //
1398  // Some action need a tag name
1399  bool special = SetID || SetEmail || SetHost || ChangePuk || ExportPuk;
1400  if (Action == kA_add || Action == kA_update ||
1401  Action == kA_read || Action == kA_remove) {
1402  if (!special && !NameTag.length() &&!Import) {
1403  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1404  PRT("+ Specified action requires a tag: "<<
1405  gActionsStr[Action]);
1406  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1407  Menu(2);
1408  return 1;
1409  }
1410  }
1411 
1412  //
1413  // If user mode, check if NameTag contains the local user
1414  // name: if not, warn the user about possible problems with
1415  // servers ignoring this kind of entries for users files
1416  if (Mode == kM_admin && SetID) {
1417  if (randomid) {
1418  // Set random ID
1419  XrdSutRndm::Init();
1421  // Add local user name
1422  struct passwd *pw = getpwuid(getuid());
1423  if (pw) {
1424  SrvID.insert(':',0);
1425  SrvID.insert(pw->pw_name,0);
1426  } else {
1427  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1428  PRT("+ WARNING: could not get local user info for srv ID +");
1429  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1430  }
1431  } else {
1432  if (SrvID.length() > 32) {
1433  SrvID.erase(32);
1434  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1435  PRT("+ WARNING: srv ID too long: truncating to 32 chars: "
1436  <<SrvID.c_str());
1437  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1438  }
1439  }
1440  }
1441 
1442  //
1443  // Setting a non default iteration number is only allowed
1444  // in admin or user mode, to avoid potential inconsistencies
1445  if (IterNum.length() > 0 && (Mode != kM_admin && Mode != kM_user)) {
1446  IterNum = "";
1447  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1448  PRT("+ WARNING: ignore iter num change request (not admin/user) +");
1449  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1450  }
1451 
1452  //
1453  // Requesting a password change only makes sense in netrc mode
1454  if (ChangePwd && Mode != kM_netrc) {
1455  ChangePwd = 0;
1456  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1457  PRT("+ WARNING: ignore password change request (not netrc) +");
1458  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1459  }
1460 
1461  //
1462  // If user mode, check if NameTag contains the local user
1463  // name: if not, warn the user about possible problems with
1464  // servers ignoring this kind of entries for users files
1465  if (Mode == kM_user && NameTag.length()) {
1466  struct passwd *pw = getpwuid(getuid());
1467  if (pw) {
1468  XrdOucString locusr = pw->pw_name;
1469  if (NameTag != locusr) {
1470  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1471  PRT("+ WARNING: name tag does not match local user name: ");
1472  PRT("+ "<<NameTag.c_str()<<" "<<locusr.c_str());
1473  PRT("+ Some servers may ignore this entry ");
1474  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1475  if (Action == kA_add)
1476  Confirm = 1;
1477  }
1478  }
1479  }
1480 
1481  //
1482  // Default action 'browse', except for specials
1483  Action = (Action == kA_undef && special) ? kA_add : Action;
1484  Action = (Action == kA_undef) ? kA_browse : Action;
1485 
1486  //
1487  // Set defaults according to mode, if required
1488  if (Mode == kM_admin) {
1489  Change = (changeset) ? Change : 1;
1490  Random = (randomset) ? Random : 1;
1491  SavePw = (savepwset) ? SavePw : 1;
1492  } else {
1493  Change = (changeset) ? Change : 0;
1494  Random = (randomset) ? Random : 0;
1495  SavePw = (savepwset) ? SavePw : 0;
1496  }
1497 
1498  //
1499  // 'Create' can be active only for 'add' or 'update'
1500  Create = (Action == kA_add || Action == kA_update) ? Create : 0;
1501 
1502  //
1503  // If defined, check nature of Path (if it exists)
1504  if (Path.length()) {
1505  //
1506  // Expand Path
1507  XrdSutExpand(Path);
1508  // Get info
1509  struct stat st;
1510  if (stat(Path.c_str(),&st) == 0) {
1511  if (S_ISDIR(st.st_mode)) {
1512  // Directory
1513  Dir = Path;
1514  } else {
1515  // Regular file
1516  File = Path;
1517  }
1518  } else {
1519  if (errno == ENOENT) {
1520  // Path does not exist: assume this is the wanted file
1521  File = Path;
1522  } else {
1523  // Path exists but we cannot access it - exit
1524  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1525  PRT("+ Cannot access requested path: "<<Path.c_str());
1526  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1527  return 1;
1528  }
1529  }
1530  }
1531 
1532  // Default File, if not specified
1533  if (!File.length()) {
1534  if (!Dir.length())
1535  Dir = DirRef;
1536  // Expand File
1537  XrdSutExpand(Dir);
1538  File = Dir;
1539  // Make the directory, if needed
1540  if (XrdSutMkdir(File.c_str(),0777) != 0) {
1541  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1542  PRT("+ Cannot create requested path: "<<File.c_str());
1543  PRT("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
1544  return 1;
1545  }
1546  // Define the files
1547  if (Mode == kM_admin) {
1548  File += AdminRef;
1549  } else if (Mode == kM_user) {
1550  File += UserRef;
1551  } else if (Mode == kM_netrc) {
1552  File += NetRcRef;
1553  } else if (Mode == kM_srvpuk) {
1554  File += SrvPukRef;
1555  }
1556  }
1557 
1558  return 0;
1559 }
1560 
1562 {
1563  // Parse crypto information in globals to load relevant factories
1564 
1565  // Use defaults if no special argument was entered
1566  if (CryptList == "")
1567  CryptList = DefCrypto;
1568 
1569  //
1570  // Vectorize
1571  int from = 0;
1572  while ((from = CryptList.tokenize(CryptMod[ncrypt], from, '|')) != -1
1573  && ncrypt < NCRYPTMAX) {
1574  ncrypt++;
1575  }
1576  RefCip = new XrdCryptoCipher *[ncrypt];
1577  CF = new XrdCryptoFactory *[ncrypt];
1578  if (CF) {
1579  int i = 0;
1580  for (; i < ncrypt; i++ ) {
1581  // Get hook to crypto factory
1583  if (!CF[i]) {
1584  PRT("// Hook for crypto factory "<<CryptMod[i]<<" undefined");
1585  continue;
1586  }
1587  }
1588  }
1589 }
1590 
1591 bool CheckOption(XrdOucString opt, const char *ref, int &ival)
1592 {
1593  // Check opt against ref
1594  // Return 1 if ok, 0 if not
1595  // Fills ival = 1 if match is exact
1596  // ival = 0 if match is exact with no<ref>
1597  // ival = -1 in the other cases
1598  bool rc = 0;
1599 
1600  int lref = (ref) ? strlen(ref) : 0;
1601  if (!lref)
1602  return rc;
1603  XrdOucString noref = ref;
1604  noref.insert("no",0);
1605 
1606  ival = -1;
1607  if (opt == ref) {
1608  ival = 1;
1609  rc = 1;
1610  } else if (opt == noref) {
1611  ival = 0;
1612  rc = 1;
1613  }
1614 
1615  return rc;
1616 }
1617 
1619  bool random, bool checkpw, bool &newpw)
1620 {
1621  // Generate (prompting or randomly) new password and add it
1622  // to entry ent
1623  // If checkpw, make sure that it is different from the existing
1624  // one (check is done on the hash, cannot decide if the change
1625  // is significant or not).
1626  // Return generated random password in ranpwd.
1627  // Randoms passwords are 8 char lengths filled with upper and
1628  // lower case letters and numbers
1629  // If !newpw, the a pwd saved during a previous call is used,
1630  // if any.
1631  // Return 1 if ok, 0 otherwise.
1632  static XrdOucString pwdref;
1633 
1634  XrdSutPFBuf oldsalt;
1635  XrdSutPFBuf oldhash;
1636  //
1637  // Save existing salt and hash, if required
1638  if (checkpw) {
1639  if (ent.buf1.len > 0 && ent.buf1.buf) {
1640  oldsalt.SetBuf(ent.buf1.buf,ent.buf1.len);
1641  if (ent.buf2.len > 0 && ent.buf2.buf) {
1642  oldhash.SetBuf(ent.buf2.buf,ent.buf2.len);
1643  } else {
1644  checkpw = 0;
1645  }
1646  } else {
1647  checkpw = 0;
1648  }
1649  }
1650  //
1651  // Save salt
1652  ent.buf1.SetBuf(salt.c_str(),salt.length());
1653  //
1654  // Prepare to get password
1655  XrdOucString passwd = "";
1656  if (newpw || !pwdref.length()) {
1657  newpw = 1;
1658  pwdref = "";
1659  }
1660  char *pwhash = 0;
1661  int pwhlen = 0;
1662  int natt = 0;
1663  while (!passwd.length()) {
1664  //
1665  //
1666  if (natt == kMAXPWDATT) {
1667  PRT("AddPassword: max number of attempts reached: "<<kMAXPWDATT);
1668  if (pwhash) delete[] pwhash;
1669  return 0;
1670  }
1671  //
1672  // Inquire password
1673  if (newpw) {
1674  if (!random) {
1675  XrdOucString prompt = "Password: ";
1676  if (natt == (kMAXPWDATT - 1))
1677  prompt.insert(" (last attempt)",prompt.find(":"));
1678  XrdSutGetPass(prompt.c_str(), passwd);
1679  if (passwd.length()) {
1680  pwdref = passwd;
1681  if (SavePw)
1682  ranpwd = passwd;
1683  newpw = 0;
1684  } else {
1685  natt++;
1686  break;
1687  }
1688  } else if (random) {
1689  XrdSutRndm::GetString(1,8,passwd);
1690  if (IterNum.length() > 0) {
1691  // Set a non-default iteration number (we are going to hash
1692  // the password with itself)
1693  passwd.insert(IterNum,0);
1694  }
1695  pwdref = passwd;
1696  ranpwd = passwd;
1697  newpw = 0;
1698  checkpw = 0; // not needed
1699  }
1700  } else {
1701  passwd = pwdref;
1702  }
1703  // Get pw hash encoding password with itself
1704  pwhash = new char[(*KDFunLen)()];
1705  pwhlen = (*KDFun)(passwd.c_str(),passwd.length(),
1706  passwd.c_str(),passwd.length(),pwhash,0);
1707  //
1708  // Check the password if required
1709  if (checkpw) {
1710  // Get hash with old salt
1711  char *osahash = new char[(*KDFunLen)()];
1712  // Encode the pw hash with the salt
1713  (*KDFun)(pwhash,pwhlen,
1714  oldsalt.buf,oldsalt.len,osahash,0);
1715  if (!memcmp(oldhash.buf,osahash,oldhash.len)) {
1716  // Do not accept this password
1717  PRT("AddPassword: Password seems to be the same"
1718  ": please enter a different one");
1719  passwd.hardreset();
1720  pwdref.hardreset();
1721  ranpwd.hardreset();
1722  newpw = 1;
1723  }
1724  // Cleanup
1725  if (osahash) delete[] osahash;
1726  }
1727  }
1728  //
1729  // Calculate new hash, now
1730  if (passwd.length()) {
1731  // Get new hash
1732  char *nsahash = new char[(*KDFunLen)()];
1733  // Encode first the hash with the salt
1734  int hlen = (*KDFun)(pwhash,pwhlen,
1735  salt.c_str(),salt.length(),nsahash,0);
1736  // Copy result in buf 2
1737  ent.buf2.SetBuf(nsahash,hlen);
1738  // Cleanup
1739  if (nsahash) delete[] nsahash;
1740  }
1741  //
1742  // Cleanup
1743  if (pwhash) delete[] pwhash;
1744  // We are done
1745  return 1;
1746 }
1747 
1748 bool AddPassword(XrdSutPFEntry &ent, bool &newpw, const char *pwd)
1749 {
1750  // Prompt new password and save in hash form to entry ent
1751  // (if pwd is defined, take password from pwd).
1752  // If !newpw, the a pwd saved during a previous call is used,
1753  // if any.
1754  // Return 1 if ok, 0 otherwise.
1755  static XrdOucString pwdref;
1756 
1757  //
1758  // Prepare to get passwrod
1759  XrdOucString passwd = "";
1760  if (newpw || !pwdref.length()) {
1761  newpw = 1;
1762  pwdref = "";
1763  }
1764  //
1765  // If we are given a password, use it
1766  if (pwd && strlen(pwd) > 0) {
1767  PRT("AddPassword: using input password ("<<strlen(pwd)<<" bytes)");
1768  passwd = pwd;
1769  }
1770  char *pwhash = 0;
1771  int pwhlen = 0;
1772  int natt = 0;
1773  while (!passwd.length()) {
1774  //
1775  //
1776  if (natt == kMAXPWDATT) {
1777  PRT("AddPassword: max number of attempts reached: "<<kMAXPWDATT);
1778  if (pwhash) delete[] pwhash;
1779  return 0;
1780  }
1781  //
1782  // Inquire password
1783  if (newpw) {
1784  XrdOucString prompt = "Password: ";
1785  if (natt == (kMAXPWDATT - 1))
1786  prompt.insert(" (last attempt)",prompt.find(":"));
1787  XrdSutGetPass(prompt.c_str(), passwd);
1788  if (passwd.length()) {
1789  pwdref = passwd;
1790  newpw = 0;
1791  } else {
1792  natt++;
1793  break;
1794  }
1795  } else {
1796  passwd = pwdref;
1797  }
1798  }
1799  //
1800  // Get pw hash encoding password with itself
1801  if (Hash) {
1802  pwhash = new char[(*KDFunLen)()];
1803  pwhlen = (*KDFun)(passwd.c_str(),passwd.length(),
1804  passwd.c_str(),passwd.length(),pwhash,0);
1805  } else {
1806  // Provided for backward compatibility with crypt-like
1807  // password hash: we just store the password in this case
1808  pwhlen = passwd.length();
1809  pwhash = new char[pwhlen];
1810  memcpy(pwhash,passwd.c_str(),pwhlen);
1811  }
1812  //
1813  // Save result in buf 1
1814  ent.buf1.SetBuf(pwhash,pwhlen);
1815  //
1816  // Cleanup
1817  if (pwhash) delete[] pwhash;
1818  // We are done
1819  return 1;
1820 }
1821 
1822 void SavePasswd(XrdOucString tag, XrdOucString pwd, bool onetime)
1823 {
1824  // Save password pwd for tag in file
1825 
1826  // Make sure we gor something
1827  if (!tag.length() || !pwd.length()) {
1828  PRT("SavePasswd: tag or pwd undefined - do nothing ("<<
1829  tag.c_str()<<","<<pwd.c_str()<<")");
1830  return;
1831  }
1832  // Make sure the directory exists, first
1833  if (!Dir.length()) {
1834  PRT("SavePasswd: main directory undefined - do nothing");
1835  return;
1836  }
1837  //
1838  // Define passwd dir
1839  PwdFile = Dir;
1840  PwdFile += GenPwdRef;
1841  //
1842  // Make the directory, if needed
1843  if (XrdSutMkdir(PwdFile.c_str(),0777) != 0) {
1844  PRT("SavePasswd: Cannot create requested path: "<<PwdFile.c_str());
1845  return;
1846  }
1847  //
1848  // File name
1849  PwdFile += tag;
1850  //
1851  // Open file, truncating if it exists already
1852  int fd = open(PwdFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
1853  if (fd < 0) {
1854  PRT("SavePasswd: could not open/create file: "<<PwdFile.c_str());
1855  PRT("SavePasswd: errno: "<<errno);
1856  return;
1857  }
1858  //
1859  // Generate buffer
1860  XrdOucString buf;
1861  buf += "********* Password information **************\n\n";
1862  buf += "host: "; buf += SrvName; buf += "\n";
1863  buf += "ID: "; buf += SrvID; buf += "\n";
1864  buf += "tag: "; buf += tag; buf += "\n";
1865  buf += "password: "; buf += pwd; buf += "\n";
1866  if (onetime) {
1867  buf += "status: "; buf += 2; buf += "\n";
1868  buf += "\n";
1869  buf += "NB: one-time password: user will be asked for \n";
1870  buf += " new password on first login \n";
1871  } else {
1872  buf += "status: "; buf += 1; buf += "\n";
1873  buf += "\n";
1874  }
1875  buf += "*********************************************";
1876  //
1877  // Write it to file
1878  // Now write the buffer to the stream
1879  while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
1880  errno = 0;
1881  //
1882  // Generate buffer
1883  buf.assign("\n",0);
1884  buf += "********* Server PUK information **************\n\n";
1885  int i = 0;
1886  for (; i < ncrypt; i++) {
1887  XrdOucString ptag = SrvName + ":";
1888  ptag += SrvID; ptag += "_"; ptag += CF[i]->ID();
1889  buf += "puk: "; buf += ptag; buf += "\n";
1890  int lpub = 0;
1891  char *pub = RefCip[i]->Public(lpub);
1892  if (pub) {
1893  buf += pub; buf += "\n";
1894  delete[] pub;
1895  }
1896  buf += "epuk\n";
1897  }
1898  buf += "\n";
1899  buf += "*********************************************";
1900  //
1901  // Write it to file
1902  // Now write the buffer to the stream
1903  while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
1904  errno = 0;
1905  //
1906  // Close file
1907  close (fd);
1908 
1909  // We are done
1910  return;
1911 }
1912 
1914  XrdSutPFEntry &ent, bool &check)
1915 {
1916  // Get antry from file, checking force
1917  // Returns 1 if it exists and should not be updated
1918  // 0 otherwise
1919 
1920  int nr = ff->ReadEntry(tag.c_str(),ent);
1921  check = 0;
1922  if (nr > 0) {
1923  if (!Force) {
1924  PRT(" Entry for tag '"<<tag.c_str()<<
1925  "' already existing in file: "<<ff->Name());
1926  PRT(" Details: "<<ent.AsString());
1927  PRT(" Use option '-force' to overwrite / update");
1928  return 1;
1929  } else {
1930  check = 1;
1931  }
1932  } else {
1933  //
1934  // Prepare Entry
1935  ent.SetName(tag.c_str());
1936  ent.cnt = 0;
1937  }
1938  return 0;
1939 }
1940 
1941 bool AskConfirm(const char *msg1, bool defact, const char *msg2)
1942 {
1943  // Prompt for confirmation of action
1944  // If defined, msg1 is printed as prompt, followed by the default action
1945  // ( [y] == do-act, for defact = true;
1946  // [n] == do-not-act, for defact = false)
1947  // If defined, msg2 is printed before prompting.
1948 
1949  bool rc = defact;
1950 
1951  if (!Confirm) {
1952  rc = 1;
1953  } else {
1954  if (msg2) PRT(msg2);
1955  XrdOucString ask;
1956  XrdOucString prompt = defact ? " [y]: " : " [n]: ";
1957  if (msg1)
1958  prompt.insert(msg1,0);
1959  XrdSutGetLine(ask,prompt.c_str());
1960  ask.lower(0);
1961  if (ask.length()) {
1962  if (defact && (ask == 'n' || ask == "no")) {
1963  rc = 0;
1964  } else if (!defact && (ask == 'y' || ask == "yes")) {
1965  rc = 1;
1966  }
1967  }
1968  }
1969  // we are done
1970  return rc;
1971 }
1972 
1973 bool ReadPasswd(XrdOucString &tag, XrdOucString &pwd, int &st)
1974 {
1975  // Read info from file PwdFile
1976  // Return tag in the form '<user>@<host><srvID>' and associated password
1977 
1978  // Make sure that the filename is defined
1979  if (PwdFile.length() <= 0) {
1980  PRT("ReadPasswd: file name undefined - do nothing");
1981  return 0;
1982  }
1983  //
1984  // Open file in read mode
1985  FILE *fd = fopen(PwdFile.c_str(),"r");
1986  if (fd == 0) {
1987  PRT("ReadPasswd: could not open file: "<<PwdFile.c_str());
1988  PRT("ReadPasswd: errno: "<<errno);
1989  return 0;
1990  }
1991  //
1992  // Read and process the info, now
1993  XrdOucString usr, host, id;
1994  char line[1024], s1[50], s2[1024];
1995  while (fgets(line, sizeof(line), fd) != 0) {
1996  if (line[strlen(line)-1] == '\n')
1997  line[strlen(line)-1] = 0;
1998  if (strlen(line) <= 0)
1999  continue;
2000  if (sscanf(line,"%s %s",s1,s2) < 2)
2001  continue;
2002  if (!strncmp(s1,"host:",5)) {
2003  host = s2;
2004  } else if (!strncmp(s1,"ID:",3)) {
2005  id = s2;
2006  } else if (!strncmp(s1,"tag:",4)) {
2007  usr = s2;
2008  } else if (!strncmp(s1,"password:",9)) {
2009  pwd = s2;
2010  } else if (!strncmp(s1,"status:",7)) {
2011  st = strtol(s2, 0, 10);
2012  }
2013  }
2014  //
2015  // Close file
2016  fclose(fd);
2017  //
2018  // Check if we found all the essential information
2019  if (usr.length() <= 0 || pwd.length() <= 0) {
2020  if (usr.length() <= 0)
2021  PRT("ReadPasswd: usr tag missing in file "<<PwdFile.c_str());
2022  if (pwd.length() <= 0)
2023  PRT("ReadPasswd: password missing in file "<<PwdFile.c_str());
2024  return 0;
2025  }
2026  //
2027  // Warning if some other information is missing
2028  if (host.length() <= 0 || id.length() <= 0) {
2029  if (host.length() <= 0)
2030  PRT("ReadPasswd: warning: host name missing in file "
2031  <<PwdFile);
2032  if (id.length() <= 0)
2033  PRT("ReadPasswd: warning: srv ID missing in file "
2034  <<PwdFile);
2035  }
2036  //
2037  // Build tag
2038  tag = usr;
2039  //
2040  // Add host, if any
2041  if (host.length() > 0) {
2042  tag += '@';
2043  tag += host;
2044  tag += ':';
2045  }
2046  //
2047  // Add srv ID, if any
2048  if (id.length() > 0) {
2049  tag += id;
2050  }
2051  //
2052  // Notify tag
2053  PRT("ReadPasswd: build tag: "<<tag);
2054 
2055 
2056  // We are done
2057  return 1;
2058 }
2059 
2060 bool ReadPuk(int &ipuk, XrdOucString *tpuk, XrdOucString *puk)
2061 {
2062  // Read server puks from file PwdFile
2063  // Return tags in the form '<host>:<srvID>_<cf_id>'
2064 
2065  // Make sure that the filename is defined
2066  if (PukFile.length() <= 0) {
2067  PRT("ReadPuk: file name undefined - do nothing");
2068  return 0;
2069  }
2070  //
2071  // Open file in read mode
2072  FILE *fd = fopen(PukFile.c_str(),"r");
2073  if (fd == 0) {
2074  PRT("ReadPuk: could not open file: "<<PukFile.c_str());
2075  PRT("ReadPuk: errno: "<<errno);
2076  return 0;
2077  }
2078  //
2079  // Read and process the info, now
2080  ipuk = 0;
2081  char line[1024], s1[50], s2[1024];
2082  while (fgets(line, sizeof(line), fd) != 0) {
2083  if (line[strlen(line)-1] == '\n')
2084  line[strlen(line)-1] = 0;
2085  if (strlen(line) <= 0)
2086  continue;
2087  if (sscanf(line,"%s %s",s1,s2) < 2)
2088  continue;
2089  if (!strncmp(s1,"puk:",4)) {
2090  if (ipuk < kMAXPUK) {
2091  tpuk[ipuk] = s2;
2092  while (fgets(line, sizeof(line), fd) != 0) {
2093  if (!strncmp(line,"puk:",4) ||
2094  !strncmp(line,"epuk",4) || strlen(line) <= 0)
2095  break;
2096  puk[ipuk] += line;
2097  }
2098  ipuk++;
2099  } else {
2100  PRT("ReadPuk: warning: max number of puks reached ("<<kMAXPUK<<")");
2101  }
2102  }
2103  }
2104  //
2105  // Close file
2106  fclose(fd);
2107  //
2108  // Build puk tags
2109  PRT("ReadPuk: found "<<ipuk<<" server puks");
2110  int i = 0;
2111  for (; i < ipuk; i++) {
2112  //
2113  // Notify tag
2114  PRT("ReadPuk: build puk tag: "<<tpuk[i]);
2115  }
2116 
2117  // We are done
2118  return 1;
2119 }
2120 
2121 bool SavePuk()
2122 {
2123  // Save ref ciphers in file named after GenPukRef and a date string
2124 
2125  // Make sure the directory exists, first
2126  if (!Dir.length()) {
2127  PRT("SavePuk: main directory undefined - do nothing");
2128  return 0;
2129  }
2130  //
2131  // Define passwd dir
2132  PukFile = Dir;
2133  PukFile += GenPukRef;
2134  //
2135  // Make the directory, if needed
2136  if (XrdSutMkdir(PukFile.c_str(),0777) != 0) {
2137  PRT("SavePuk: Cannot create requested path: "<<PukFile);
2138  return 0;
2139  }
2140  //
2141  // File name
2142  PukFile += "puk.";
2143  int now = time(0);
2144  char *tstr = new char[20];
2145  if (!tstr) {
2146  PRT("SavePuk: Cannot create buffer for time string");
2147  return 0;
2148  }
2149  XrdSutTimeString(now, tstr, 1);
2150  PukFile += tstr;
2151  delete [] tstr;
2152  //
2153  // Open file, truncating if it exists already
2154  int fd = open(PukFile.c_str(),O_WRONLY | O_CREAT | O_TRUNC, 0600);
2155  if (fd < 0) {
2156  PRT("SavePuk: could not open/create file: "<<PukFile);
2157  PRT("SavePuk: errno: "<<errno);
2158  return 0;
2159  }
2160  //
2161  // Temporary array of buckets
2162  XrdSutBucket **bck = new XrdSutBucket *[ncrypt];
2163  if (!bck) {
2164  PRT("SavePuk: Cannot create array of temporary buckets");
2165  return 0;
2166  }
2167  //
2168  // First loop over ciphers to determine the size
2169  int lout = 0, i = 0;
2170  for (; i < ncrypt; i++) {
2171  //
2172  // Make sure it is defined
2173  if (!CF[i] || !RefCip[i]) continue;
2174  //
2175  // Get bucket out of cipher
2176  bck[i] = RefCip[i]->AsBucket();
2177  if (!bck[i]) continue;
2178  //
2179  // Count
2180  lout += (bck[i]->size + 2*sizeof(kXR_int32));
2181  }
2182  //
2183  // Get the buffer
2184  char *bout = new char[lout];
2185  if (!bout) {
2186  PRT("SavePuk: Cannot create output buffer");
2187  close(fd);
2188  return 0;
2189  }
2190  //
2191  // Loop over ciphers to fill the buffer
2192  int lp = 0;
2193  for (i = 0; i < ncrypt; i++) {
2194  //
2195  // Make sure it is defined
2196  if (!CF[i] || !bck[i]) continue;
2197  //
2198  // The crypto ID first
2199  kXR_int32 id = CF[i]->ID();
2200  memcpy(bout+lp,&id,sizeof(kXR_int32));
2201  lp += sizeof(kXR_int32);
2202  //
2203  // The length second
2204  kXR_int32 lpuk = bck[i]->size;
2205  memcpy(bout+lp,&lpuk,sizeof(kXR_int32));
2206  lp += sizeof(kXR_int32);
2207  //
2208  // Finally the content
2209  memcpy(bout+lp,bck[i]->buffer,lpuk);
2210  lp += lpuk;
2211  //
2212  // Cleanup
2213  delete bck[i];
2214  bck[i] = 0;
2215  }
2216  delete[] bck;
2217  //
2218  // Write it to file
2219  // Now write the buffer to the stream
2220  while (write(fd, bout, lout) < 0 && errno == EINTR)
2221  errno = 0;
2222  PRT("SavePuk: "<<lout<<" bytes written to file "<<PukFile);
2223  //
2224  // Close file
2225  close (fd);
2226 
2227  // We are done
2228  return 1;
2229 }
2230 
2231 bool ReadPuk()
2232 {
2233  // Read ref ciphers from file PukFile
2234 
2235  // Make sure that the filename is defined
2236  if (PukFile.length() <= 0) {
2237  PRT("ReadPuk: file name undefined - do nothing");
2238  return 0;
2239  }
2240  //
2241  // Open file in read mode
2242  int fd = open(PukFile.c_str(),O_RDONLY);
2243  if (fd < 0) {
2244  PRT("ReadPuk: could not open file: "<<PukFile.c_str());
2245  PRT("ReadPuk: errno: "<<errno);
2246  return 0;
2247  }
2248 
2249  //
2250  // Read out info now
2251  int nr = 0, nrdt = 0, ncip = 0;
2252  kXR_int32 id = 0, lpuk = 0;
2253  // the status ...
2254  while ((nr = read(fd,&id,sizeof(kXR_int32))) == sizeof(kXR_int32)) {
2255  nrdt += nr;
2256  // Read puk length
2257  if ((nr = read(fd,&lpuk,sizeof(kXR_int32))) != sizeof(kXR_int32)) {
2258  PRT("ReadPuk: could not read puk length - corrupton ? ");
2259  close(fd);
2260  return 0;
2261  }
2262  nrdt += nr;
2263  // Read puk buffer
2264  char *puk = new char[lpuk];
2265  if (!puk) {
2266  PRT("ReadPuk: could not allocate buffer for puk");
2267  close(fd);
2268  return 0;
2269  }
2270  if ((nr = read(fd, puk, lpuk)) != lpuk) {
2271  PRT("ReadPuk: could not read puk buffer - corrupton ? ");
2272  close(fd);
2273  return 0;
2274  }
2275  nrdt += nr;
2276  // Save in bucket
2277  XrdSutBucket *bck = new XrdSutBucket(puk, lpuk);
2278  if (!bck) {
2279  PRT("ReadPuk: could not create bucket for puk");
2280  delete[] puk;
2281  close(fd);
2282  return 0;
2283  }
2284  // Find crypto factory index
2285  int i = ncrypt - 1;
2286  while (i >= 0) {
2287  if (CF[i] && CF[i]->ID() == id) break;
2288  i--;
2289  }
2290  if (i < 0) {
2291  PRT("ReadPuk: warning: factory with ID "<< id << " not found");
2292  delete bck;
2293  continue;
2294  }
2295  // Instantiate cipher from bucket
2296  RefCip[i] = CF[i]->Cipher(bck);
2297  if (!RefCip[i]) {
2298  PRT("ReadPuk: warning: could not instantiate cipher"
2299  " from bucket for factory "<<CF[i]->Name());
2300  } else {
2301  PRT("ReadPuk: instantiate cipher for factory "<<CF[i]->Name());
2302  }
2303  // Count good ciphers
2304  ncip++;
2305  delete bck;
2306  }
2307  //
2308  // Close file
2309  close (fd);
2310 
2311  PRT("ReadPuk: "<<nrdt<<" bytes read from file "<<PukFile);
2312  PRT("ReadPuk: "<<ncip<<" ciphers instantiated");
2313 
2314  // We are done
2315  return 1;
2316 }
2317 
2319 {
2320  // Generate new ref ciphers for all the defined factories
2321 
2322  int ncf = 0, i = 0;
2323  for (; i < ncrypt; i++ ) {
2324  // Get hook to crypto factory
2326  if (!CF[i]) {
2327  PRT("// Hook for crypto factory "<<CryptMod[i]<<" undefined");
2328  continue;
2329  }
2330  //
2331  // Generate reference cipher
2332  RefCip[i] = CF[i]->Cipher(0,0,0);
2333  if (!RefCip[i]) continue;
2334  //
2335  // Count success
2336  ncf++;
2337  }
2338 
2339  // We are done
2340  return ncf;
2341 }
2342 
2343 int LocateFactoryIndex(char *tag, int &id)
2344 {
2345  // Searches tag for "_<id>" final strings
2346  // Extracts id and locate position in crypto array
2347 
2348  //
2349  // Locate factory ID
2350  XrdOucString sid(tag);
2351  sid.erase(0,sid.rfind('_')+1);
2352  id = atoi(sid.c_str());
2353  int j = ncrypt - 1;
2354  while (j >= 0) {
2355  if (CF[j] && CF[j]->ID() == id) break;
2356  j--;
2357  }
2358  if (j < 0)
2359  PRT("// warning: factory with ID "<< id << " not found");
2360 
2361  return j;
2362 }
2363 
2364 bool ExpPuk(const char *puk, bool read)
2365 {
2366  // Export public part of key contained in file 'puk'. The file
2367  // name can be absolute or relative to the standard 'genpuk' or
2368  // a date to be looked for in the genpuk directory. The public
2369  // key is exported in a file adding the extension ".export"
2370  // to 'puk'. If the file name is not defined the most recent
2371  // key in the standard genpuk directory is exported.
2372  // Return 0 in case of failure, 1 in case of success.
2373 
2374  // Read the keys in, if needed
2375  if (read) {
2376  // Standard genpuk dir
2377  XrdOucString genpukdir = Dir;
2378  genpukdir += GenPukRef;
2379 
2380  // Locate the file with the full key
2381  if (puk && strlen(puk) > 0) {
2382  // If not absolute, expand with respect to the standard genpuk dir
2383  if (puk[0] != '/')
2384  PukFile = genpukdir;
2385  PukFile += puk;
2386  } else {
2387  // Scan the standard genpuk to find the most recent key
2388  DIR *dir = opendir(genpukdir.c_str());
2389  if (!dir) {
2390  PRT("ExpPuk: cannot open standard genpuk dir "<<genpukdir);
2391  return 0;
2392  }
2393  dirent *ent = 0;
2394  time_t latest = -1;
2395  while ((ent = readdir(dir))) {
2396  // Skip non-key files
2397  if (strncmp(ent->d_name, "puk.", 4))
2398  continue;
2399  // Get the modification date
2400  XrdOucString fn = genpukdir;
2401  fn += ent->d_name;
2402  struct stat st;
2403  if (stat(fn.c_str(), &st) != 0) {
2404  PRT("ExpPuk: cannot stat "<<fn<<" - skipping");
2405  continue;
2406  }
2407  if (st.st_mtime > latest) {
2408  PukFile = fn;
2409  latest = st.st_mtime;
2410  }
2411  }
2412  }
2413 
2414  // Read the keys in
2415  if (!ReadPuk()) {
2416  PRT("ExpPuk: problem reading the key in");
2417  return 0;
2418  }
2419  }
2420 
2421  // Build the export file name
2422  XrdOucString expfile = PukFile;
2423  expfile += ".export";
2424  PRT("ExpPuk: exporting key from file "<<PukFile);
2425 
2426  // Now we save the public part in the export files
2427  // Open file, truncating if it exists already
2428  int fd = open(expfile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
2429  if (fd < 0) {
2430  PRT("ExpPuk: could not open/create file: "<<expfile.c_str());
2431  PRT("ExpPuk: errno: "<<errno);
2432  return 0;
2433  }
2434  //
2435  // Generate buffer
2436  XrdOucString buf;
2437  buf.assign("\n",0);
2438  buf += "********* Server PUK information **************\n\n";
2439  int i = 0;
2440  for (; i < ncrypt; i++) {
2441  XrdOucString ptag = SrvName + ":";
2442  ptag += SrvID; ptag += "_"; ptag += CF[i]->ID();
2443  buf += "puk: "; buf += ptag; buf += "\n";
2444  int lpub = 0;
2445  char *pub = RefCip[i]->Public(lpub);
2446  if (pub) {
2447  buf += pub; buf += "\n";
2448  delete[] pub;
2449  }
2450  buf += "epuk\n";
2451  }
2452  buf += "\n";
2453  buf += "*********************************************";
2454  //
2455  // Write it to file
2456  // Now write the buffer to the stream
2457  while (write(fd, buf.c_str(), buf.length()) < 0 && errno == EINTR)
2458  errno = 0;
2459  //
2460  // Close file
2461  close (fd);
2462 
2463  // We are done
2464  return 1;
2465 }
int kXR_int32
Definition: XPtypes.hh:89
int(* XrdCryptoKDFunLen_t)()
Definition: XrdCryptoAux.hh:59
int(* XrdCryptoKDFun_t)(const char *pass, int plen, const char *salt, int slen, char *key, int klen)
Definition: XrdCryptoAux.hh:60
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int fclose(FILE *stream)
ssize_t write(int fildes, const void *buf, size_t nbyte)
ssize_t read(int fildes, void *buf, size_t nbyte)
DIR * opendir(const char *path)
#define close(a)
Definition: XrdPosix.hh:43
#define fopen(a, b)
Definition: XrdPosix.hh:49
kModes
XrdOucString AdminRef
bool Backup
XrdOucString Path
int NoBackup
bool CheckOption(XrdOucString opt, const char *ref, int &ival)
int ncrypt
bool SavePuk()
XrdOucString DefCrypto
XrdOucString PukFile
XrdOucString SrvName
XrdOucString EmailTag
XrdOucString NameTag
int main(int argc, char **argv)
bool Random
int Mode
const char * gModesStr[]
int GeneratePuk()
bool SetID
XrdOucString PwdFile
XrdOucString Email
XrdOucString UserRef
bool Force
bool SetEmail
XrdOucString GenPukRef
@ kM_netrc
@ kM_undef
@ kM_srvpuk
@ kM_admin
@ kM_user
@ kM_help
bool Confirm
XrdOucString PukTag
int Action
int nHostPuk
bool AskConfirm(const char *msg1, bool defact, const char *msg2=0)
const char * gActionsStr[]
XrdOucString CopyTag
void Menu(int opt=0)
bool SavePw
XrdOucString CryptList
void SavePasswd(XrdOucString tag, XrdOucString pwd, bool onetime)
XrdOucString IDTag
XrdOucString SrvPukRef
XrdOucString Dir
bool GetEntry(XrdSutPFile *ff, XrdOucString tag, XrdSutPFEntry &ent, bool &check)
bool SetHost
XrdOucString File
bool AddPassword(XrdSutPFEntry &ent, XrdOucString salt, XrdOucString &ranpwd, bool random, bool checkpw, bool &newpw)
#define PRT(x)
XrdCryptoKDFunLen_t KDFunLen
#define kMAXPWDATT
XrdCryptoFactory ** CF
int LocateFactoryIndex(char *tag, int &id)
bool ExportPuk
XrdOucString TagHostPuk[kMAXPUK]
bool Passwd
XrdCryptoCipher ** RefCip
XrdOucString DirRef
@ kA_copy
@ kA_disable
@ kA_remove
@ kA_update
@ kA_read
@ kA_trim
@ kA_add
@ kA_undef
@ kA_browse
XrdOucString CryptMod[NCRYPTMAX]
bool Change
bool ReadPasswd(XrdOucString &tag, XrdOucString &pwd, int &st)
XrdOucString HostPuk[kMAXPUK]
#define NCRYPTMAX
XrdOucString IterNum
XrdOucString SrvID
bool Import
XrdOucString NetRcRef
int ParseArguments(int argc, char **argv)
bool DontAsk
#define kMAXPUK
void ParseCrypto()
XrdOucString HostTag
XrdCryptoKDFun_t KDFun
XrdOucString GenPwdRef
bool ReadPuk(int &npuk, XrdOucString *tpuk, XrdOucString *puk)
bool ChangePwd
bool Hash
bool ExpPuk(const char *puk=0, bool read=1)
int DebugON
bool ChangePuk
bool Create
int XrdSutGetPass(const char *prompt, XrdOucString &passwd)
Definition: XrdSutAux.cc:156
int XrdSutExpand(XrdOucString &path)
Definition: XrdSutAux.cc:366
int XrdSutMkdir(const char *dir, unsigned int mode, const char *opt)
Definition: XrdSutAux.cc:493
int XrdSutTimeString(int t, char *st, int opt)
Definition: XrdSutAux.cc:311
void XrdSutSetTrace(kXR_int32 trace)
Definition: XrdSutAux.cc:93
int XrdSutGetLine(XrdOucString &line, const char *prompt)
Definition: XrdSutAux.cc:185
#define sutTRACE_Debug
Definition: XrdSutAux.hh:99
@ kPFE_special
@ kPFE_allowed
@ kPFE_disabled
@ kPFE_onetime
@ kPFE_ok
@ kPFErrNoFile
Definition: XrdSutPFile.hh:67
#define kPFEcreate
Definition: XrdSutPFile.hh:59
#define ID
virtual XrdSutBucket * AsBucket()
virtual char * Public(int &lpub)
virtual XrdCryptoKDFun_t KDFun()
virtual XrdCryptoCipher * Cipher(const char *t, int l=0)
virtual XrdCryptoKDFunLen_t KDFunLen()
static XrdCryptoFactory * GetCryptoFactory(const char *factoryname)
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
int erase(int start=0, int size=0)
int rfind(const char c, int start=STR_NPOS)
void hardreset()
int find(const char c, int start=0, bool forward=1)
int length() const
int tokenize(XrdOucString &tok, int from, char del=':')
void lower(int pos, int size=0)
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)
void SetBuf(const char *b=0, kXR_int32 l=0)
kXR_int32 len
kXR_int32 mtime
XrdSutPFBuf buf3
XrdSutPFBuf buf1
char * AsString() const
void SetName(const char *n=0)
XrdSutPFBuf buf2
XrdSutPFBuf buf4
kXR_int32 Browse(void *out=0)
kXR_int32 Trim(const char *fbak=0)
kXR_int32 WriteEntry(XrdSutPFEntry ent)
Definition: XrdSutPFile.cc:585
bool IsValid() const
Definition: XrdSutPFile.hh:170
const char * Name() const
Definition: XrdSutPFile.hh:168
kXR_int32 SearchEntries(const char *name, char opt, kXR_int32 *ofs=0, kXR_int32 nofs=1)
kXR_int32 ReadEntry(const char *name, XrdSutPFEntry &ent, int opt=0)
Definition: XrdSutPFile.cc:909
bool Init(const char *n, kXR_int32 openmode=kPFEcreate, kXR_int32 createmode=0600, bool hashtab=1)
Definition: XrdSutPFile.cc:236
kXR_int32 RemoveEntry(const char *name)
kXR_int32 LastError() const
Definition: XrdSutPFile.hh:172
static bool Init(bool force=0)
Definition: XrdSutRndm.cc:62
static int GetString(int opt, int len, XrdOucString &s)
Definition: XrdSutRndm.cc:120