XRootD
XrdSecProtocolpwd.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c P r o t o c o l p w d . 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 #include <unistd.h>
30 #include <cctype>
31 #include <cerrno>
32 #include <cstdlib>
33 #include <strings.h>
34 #include <cstdio>
35 #include <sys/param.h>
36 #include <pwd.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <sys/times.h>
41 
42 #include "XrdVersion.hh"
43 
44 #include "XrdSys/XrdSysHeaders.hh"
45 #include "XrdSys/XrdSysLogger.hh"
46 #include "XrdSys/XrdSysError.hh"
47 #include "XrdSys/XrdSysPwd.hh"
48 #include "XrdOuc/XrdOucStream.hh"
49 
50 #include "XrdSys/XrdSysPriv.hh"
51 
52 #include "XrdSut/XrdSutPFCache.hh"
53 
56 
57 /******************************************************************************/
58 /* T r a c i n g I n i t O p t i o n s */
59 /******************************************************************************/
60 #ifndef NODEBUG
61 #define POPTS(t,y) {if (t) {t->Beg(epname); std::cerr <<y; t->End();}}
62 #else
63 #define POPTS(t,y)
64 #endif
65 
66 /******************************************************************************/
67 /* S t a t i c D a t a */
68 /******************************************************************************/
69 
70 static String Prefix = "xrd";
73 static String AdminRef = ProtoID + "admin";
74 static String SrvPukRef= ProtoID + "srvpuk";
75 static String UserRef = ProtoID + "user";
76 static String NetRcRef = ProtoID + "netrc";
77 
78 static const char *pwdClientSteps[] = {
79  "kXPC_none",
80  "kXPC_normal",
81  "kXPC_verifysrv",
82  "kXPC_signedrtag",
83  "kXPC_creds",
84  "kXPC_autoreg",
85  "kXPC_failureack",
86  "kXPC_reserved"
87 };
88 
89 static const char *pwdServerSteps[] = {
90  "kXPS_none",
91  "kXPS_init",
92  "kXPS_credsreq",
93  "kXPS_rtag",
94  "kXPS_signedrtag",
95  "kXPS_newpuk",
96  "kXPS_puk",
97  "kXPS_failure",
98  "kXPS_reserved"
99 };
100 
101 static const char *gPWErrStr[] = {
102  "parsing buffer", // 10000
103  "decoding buffer", // 10001
104  "loading crypto factory", // 10002
105  "protocol mismatch", // 10003
106  "resolving user / host", // 10004
107  "user missing", // 10005
108  "host missing", // 10006
109  "unknown user", // 10007
110  "creating bucket", // 10008
111  "duplicating bucket", // 10009
112  "creating buffer", // 10010
113  "serializing buffer", // 10011
114  "generating cipher", // 10012
115  "exporting public key", // 10013
116  "encrypting random tag", // 10014
117  "random tag mismatch", // 10015
118  "random tag missing", // 10016
119  "cipher missing", // 10017
120  "getting credentials", // 10018
121  "credentials missing", // 10019
122  "wrong password for user", // 10020
123  "checking cache", // 10021
124  "cache entry for link missing", // 10022
125  "session handshaking ID missing", // 10023
126  "session handshaking ID mismatch", // 10024
127  "unknown step option", // 10025
128  "marshaling integer", // 10026
129  "unmarshaling integer", // 10027
130  "saving new credentials", // 10028
131  "salt missing", // 10029
132  "buffer empty", // 10030
133  "obtaining reference cipher", // 10031
134  "obtaining cipher public info", // 10032
135  "adding bucket to list", // 10033
136  "finalizing cipher from public info", // 10034
137  "error during initialization", // 10035
138  "wrong credentials", // 10035
139  "error" // 10036
140 };
141 
142 // Masks for options
143 static const short kOptsServer = 0x0001;
144 static const short kOptsUserPwd = 0x0002;
145 static const short kOptsAutoReg = 0x0004;
146 static const short kOptsAregAll = 0x0008;
147 static const short kOptsVeriSrv = 0x0020;
148 static const short kOptsVeriClt = 0x0040;
149 static const short kOptsClntTty = 0x0080;
150 static const short kOptsExpCred = 0x0100;
151 static const short kOptsCrypPwd = 0x0200;
152 static const short kOptsChngPwd = 0x0400;
153 static const short kOptsAFSPwd = 0x0800;
154 // One day in secs
155 static const int kOneDay = 86400;
156 
157 /******************************************************************************/
158 /* S t a t i c C l a s s D a t a */
159 /******************************************************************************/
160 XrdSysMutex XrdSecProtocolpwd::pwdContext;
161 String XrdSecProtocolpwd::FileAdmin= "";
162 String XrdSecProtocolpwd::FileExpCreds= "";
163 String XrdSecProtocolpwd::FileUser = "";
164 String XrdSecProtocolpwd::FileCrypt= "/.xrdpass";
165 String XrdSecProtocolpwd::FileSrvPuk= "";
166 String XrdSecProtocolpwd::SrvID = "";
167 String XrdSecProtocolpwd::SrvEmail = "";
168 String XrdSecProtocolpwd::DefCrypto= "ssl";
169 String XrdSecProtocolpwd::DefError = "insufficient credentials - contact ";
170 XrdSutPFile XrdSecProtocolpwd::PFAdmin(0); // Admin file (server)
171 XrdSutPFile XrdSecProtocolpwd::PFAlog(0); // Autologin file (client)
172 XrdSutPFile XrdSecProtocolpwd::PFSrvPuk(0); // File with server public keys (client)
173 //
174 // Crypto related info
175 int XrdSecProtocolpwd::ncrypt = 0; // Number of factories
176 int XrdSecProtocolpwd::cryptID[XrdCryptoMax] = {0}; // their IDs
177 String XrdSecProtocolpwd::cryptName[XrdCryptoMax] = {0}; // their names
178 XrdCryptoCipher *XrdSecProtocolpwd::refcip[XrdCryptoMax] = {0}; // ref for session ciphers
179 //
180 // Caches for info files
181 XrdSutPFCache XrdSecProtocolpwd::cacheAdmin; // Admin file
182 XrdSutPFCache XrdSecProtocolpwd::cacheSrvPuk; // SrvPuk file
183 XrdSutPFCache XrdSecProtocolpwd::cacheUser; // User files
184 XrdSutPFCache XrdSecProtocolpwd::cacheAlog; // Autologin file
185 //
186 // Running options / settings
187 int XrdSecProtocolpwd::Debug = 0; // [CS] Debug level
188 bool XrdSecProtocolpwd::Server = 1; // [CS] If server mode
189 int XrdSecProtocolpwd::UserPwd = 0; // [S] Check passwd file in user's <xrdsecdir>
190 bool XrdSecProtocolpwd::SysPwd = 0; // [S] Check passwd file in user's <xrdsecdir>
191 int XrdSecProtocolpwd::VeriClnt = 2; // [S] Client authenticity verification level:
192  // 0 none, 1 timestamp, 2 random tag
193 int XrdSecProtocolpwd::VeriSrv = 1; // [C] Server authenticity verification level:
194  // 0 none, 1 random tag
195 int XrdSecProtocolpwd::AutoReg = kpAR_none; // [S] Autoreg mode
196 int XrdSecProtocolpwd::LifeCreds = 0; // [S] if > 0, time interval of validity for creds
197 int XrdSecProtocolpwd::MaxPrompts = 3; // [C] Repeating prompt
198 int XrdSecProtocolpwd::MaxFailures = 10;// [S] Max passwd failures before blocking
199 int XrdSecProtocolpwd::AutoLogin = 0; // [C] do-not-check/check/update autologin info
200 int XrdSecProtocolpwd::TimeSkew = 300; // [CS] Allowed skew in secs for time stamps
201 bool XrdSecProtocolpwd::KeepCreds = 0; // [S] Keep / Do-Not-Keep client creds
202 int XrdSecProtocolpwd::FmtExpCreds = 0; // [S] Format for exported credentials
203 //
204 // Debug an tracing
205 XrdSysError XrdSecProtocolpwd::eDest(0, "secpwd_");
206 XrdSysLogger XrdSecProtocolpwd::Logger;
207 XrdOucTrace *XrdSecProtocolpwd::PWDTrace = 0;
208 
210 
211 /******************************************************************************/
212 /* S t a t i c F u n c t i o n s */
213 /******************************************************************************/
214 //_____________________________________________________________________________
215 static const char *ClientStepStr(int kclt)
216 {
217  // Return string with client step
218  static const char *ukn = "Unknown";
219 
220  kclt = (kclt < 0) ? 0 : kclt;
221  kclt = (kclt > kXPC_reserved) ? 0 : kclt;
222  kclt = (kclt >= kXPC_normal) ? (kclt - kXPC_normal + 1) : kclt;
223 
224  if (kclt < 0 || kclt > (kXPC_reserved - kXPC_normal + 1))
225  return ukn;
226  else
227  return pwdClientSteps[kclt];
228 }
229 
230 //_____________________________________________________________________________
231 static const char *ServerStepStr(int ksrv)
232 {
233  // Return string with server step
234  static const char *ukn = "Unknown";
235 
236  ksrv = (ksrv < 0) ? 0 : ksrv;
237  ksrv = (ksrv > kXPS_reserved) ? 0 : ksrv;
238  ksrv = (ksrv >= kXPS_init) ? (ksrv - kXPS_init + 1) : ksrv;
239 
240  if (ksrv < 0 || ksrv > (kXPS_reserved - kXPS_init + 1))
241  return ukn;
242  else
243  return pwdServerSteps[ksrv];
244 }
245 
246 /******************************************************************************/
247 /* P r o t o c o l I n i t i a l i z a t i o n M e t h o d s */
248 /******************************************************************************/
249 
250 
251 //_____________________________________________________________________________
253  XrdNetAddrInfo &endPoint,
254  const char *parms) : XrdSecProtocol("pwd")
255 {
256  // Default constructor
257  EPNAME("XrdSecProtocolpwd");
258 
259  if (QTRACE(Authen)) { PRINT("constructing: "<<this); }
260 
261  // Create instance of the handshake vars
262  if ((hs = new pwdHSVars())) {
263  // Update time stamp
264  hs->TimeStamp = time(0);
265  // Local handshake variables
266  hs->CryptoMod = ""; // crypto module in use
267  hs->User = ""; // remote username
268  hs->Tag.resize(256); // tag for credentials
269  hs->RemVers = -1; // Version run by remote counterpart
270  hs->CF = 0; // crypto factory
271  hs->Hcip = 0; // handshake cipher
272  hs->Rcip = 0; // reference cipher
273  hs->ID = ""; // Handshake ID (dummy for clients)
274  hs->Cref = 0; // Cache reference
275  hs->Pent = 0; // Pointer to relevant file entry
276  hs->RtagOK = 0; // Rndm tag checked / not checked
277  hs->Tty = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
278  hs->Step = 0; // Current step
279  hs->LastStep = 0; // Step required at previous iteration
280  } else {
281  PRINT("could not create handshake vars object");
282  }
283 
284  // Used by servers to store forwarded credentials
285  clientCreds = 0;
286 
287  // Save host name and address
288  if (hname) {
289  Entity.host = strdup(hname);
290  } else {
291  NOTIFY("warning: host name undefined");
292  }
293  epAddr = endPoint;
294  Entity.addrInfo = &epAddr;
295  // Init client name
296  CName[0] = '?'; CName[1] = '\0';
297 
298  //
299  // Notify, if required
300  DEBUG("constructing: host: "<<hname);
301  DEBUG("p: "<<XrdSecPROTOIDENT<<", plen: "<<XrdSecPROTOIDLEN);
302  //
303  // basic settings
304  options = opts;
305 
306  //
307  // Mode specific initializations
308  if (Server) {
309  srvMode = 1;
310  DEBUG("mode: server");
311  } else {
312  srvMode = 0;
313  DEBUG("mode: client");
314  if (AutoLogin > 0) {
315  DEBUG("using autologin file: "<<PFAlog.Name());
316  if (AutoLogin > 1) {
317  DEBUG("running in update-autologin mode");
318  }
319  }
320  if (VeriSrv > 0) {
321  DEBUG("server verification ON");
322  } else {
323  DEBUG("server verification OFF");
324  }
325  // Decode received buffer
326  if (parms) {
327  XrdOucString p("&P=pwd,");
328  p += parms;
329  hs->Parms = new XrdSutBuffer(p.c_str(), p.length());
330  }
331  }
332 
333  // We are done
334  String vers = Version;
335  vers.insert('.',vers.length()-2);
336  vers.insert('.',vers.length()-5);
337  DEBUG("object created: v"<<vers.c_str());
338 }
339 
340 //_____________________________________________________________________________
342 {
343  // Static method to the configure the static part of the protocol
344  // Called once by XrdSecProtocolpwdInit
345  EPNAME("Init");
346  XrdSutPFCacheRef pfeRef;
347  char *Parms = 0;
348  //
349  // Debug an tracing
350  Debug = (opt.debug > -1) ? opt.debug : Debug;
351 
352  // We must have the tracing object at this point
353  // (initialized in XrdSecProtocolgsiInit)
354  if (!pwdTrace) {
355  ErrF(erp,kPWErrInit,"tracing object (pwdTrace) not initialized! cannot continue");
356  return Parms;
357  }
358 
359  // Set debug mask ... also for auxilliary libs
360  int trace = 0, traceSut = 0, traceCrypto = 0;
361  if (Debug >= 3) {
362  trace = cryptoTRACE_Dump;
363  traceSut = sutTRACE_Dump;
364  traceCrypto = cryptoTRACE_Dump;
365  PWDTrace->What = TRACE_ALL;
366  } else if (Debug >= 2) {
367  trace = cryptoTRACE_Debug;
368  traceSut = sutTRACE_Debug;
369  traceCrypto = cryptoTRACE_Debug;
370  PWDTrace->What = TRACE_Debug;
371  PWDTrace->What |= TRACE_Authen;
372  } else if (Debug >= 1) {
373  trace = cryptoTRACE_Debug;
374  traceSut = sutTRACE_Notify;
375  traceCrypto = cryptoTRACE_Notify;
376  PWDTrace->What = TRACE_Debug;
377  }
378 
379  // ... also for auxilliary libs
380  XrdSutSetTrace(traceSut);
381  XrdCryptoSetTrace(traceCrypto);
382 
383  // Get user info
384  struct passwd *pw;
385  XrdSysPwd thePwd(getuid(), &pw);
386 
387  if (!pw) {
388  PRINT("no user info available - invalid ");
389  ErrF(erp, kPWErrInit, "could not get user info from pwuid");
390  return Parms;
391  }
392 
393  //
394  // Operation mode
395  Server = (opt.mode == 's');
396 
397  //
398  // Directory with admin pwd files
399  bool argdir = 0;
400  String infodir(512);
401  if (opt.dir) {
402  infodir = opt.dir;
403  // Expand
404  if (XrdSutExpand(infodir) != 0) {
405  PRINT("cannot expand "<<opt.dir);
406  infodir = "";
407  }
408  argdir = 1;
409  } else {
410  // use default dir $(HOME)/.<prefix>
411  infodir = XrdSutHome();
412  infodir += ("/." + Prefix);
413  }
414  if (!infodir.endswith("/")) infodir += "/";
415  //
416  // If defined, check existence of the infodir and admin file
417  if (infodir.length()) {
418  // Acquire the privileges, if needed
419  XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
420  if (priv.Valid()) {
421  struct stat st;
422  if (stat(infodir.c_str(),&st) == -1) {
423  if (errno == ENOENT) {
424  if (argdir) {
425  DEBUG("infodir non existing: "<<infodir.c_str());
426  } else {
427  DEBUG("creating infodir: "<<infodir.c_str());
428  if (XrdSutMkdir(infodir.c_str(),0777) != 0) {
429  DEBUG("cannot create infodir (errno: "<<errno<<")");
430  infodir = "";
431  argdir = 0;
432  }
433  }
434  } else {
435  DEBUG("cannot stat infodir "<<infodir<<" (errno: "<<errno<<")");
436  infodir = "";
437  argdir = 0;
438  }
439  }
440  }
441  }
442  DEBUG("using infodir: "<<infodir.c_str());
443 
444  //
445  // Server specific options
446  if (Server) {
447  //
448  // Auto registration
449  AutoReg = (opt.areg > -1) ? opt.areg : AutoReg;
450  //
451  // Client verification level
452  VeriClnt = (opt.vericlnt > -1) ? opt.vericlnt : VeriClnt;
453  //
454  // Whether to check pwd files in users' $HOME
455  UserPwd = (opt.upwd > -1) ? opt.upwd : UserPwd;
456  //
457  // Whether to check system pwd files (if allowed)
458  SysPwd = (opt.syspwd > -1) ? opt.syspwd : SysPwd;
459  if (SysPwd) {
460  // Make sure this setting makes sense
461  if (pw) {
462 #ifdef HAVE_SHADOWPW
463  // Acquire the privileges, if needed
464  XrdSysPrivGuard priv((uid_t) 0, (gid_t) 0);
465  if (priv.Valid()) {
466  // System V Rel 4 style shadow passwords
467  struct spwd *spw = getspnam(pw->pw_name);
468  if (!spw) {
469  SysPwd = 0;
470  DEBUG("no privileges to access shadow passwd file");
471  }
472  } else {
473  DEBUG("problems acquiring credentials"
474  " to access the system password file");
475  }
476 #else
477  // Normal passwd file
478  if (!pw->pw_passwd &&
479  (pw->pw_passwd && strlen(pw->pw_passwd) <= 1)) {
480  SysPwd = 0;
481  DEBUG("no privileges to access system passwd file");
482  }
483 #endif
484  } else
485  SysPwd = 0;
486  }
487  //
488  // Credential lifetime
489  LifeCreds = (opt.lifecreds > -1) ? opt.lifecreds : LifeCreds;
490  //
491  // Max number of failures
492  MaxFailures = (opt.maxfailures > -1) ? opt.maxfailures : MaxFailures;
493 
494  //
495  // If defined, check existence of the infodir and admin file
496  if (infodir.length()) {
497  // Acquire the privileges, if needed
498  XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
499  if (priv.Valid()) {
500  struct stat st;
501  //
502  // Define admin file and check its existence
503  FileAdmin = infodir + AdminRef;
504  if (stat(FileAdmin.c_str(),&st) == -1) {
505  if (errno == ENOENT) {
506  PRINT("FileAdmin non existing: "<<FileAdmin.c_str());
507  } else {
508  PRINT("cannot stat FileAdmin (errno: "<<errno<<")");
509  }
510  FileAdmin = "";
511  if (UserPwd == 0 && !SysPwd) {
512  PRINT("no passwd info available - invalid ");
513  ErrF(erp,kPWErrInit,"could not find a valid password file");
514  return Parms;
515  }
516  }
517  if (FileAdmin.length() > 0) {
518  //
519  // Load server ID
520  PFAdmin.Init(FileAdmin.c_str(),0);
521  if (PFAdmin.IsValid()) {
522  //
523  // Init cache for admin file
524  if (cacheAdmin.Load(FileAdmin.c_str()) != 0) {
525  PRINT("problems init cache for file admin ");
526  ErrF(erp,kPWErrError,"initializing cache for file admin");
527  return Parms;
528  }
529  if (QTRACE(Authen)) { cacheAdmin.Dump(); }
530  XrdSutPFEntry *ent = cacheAdmin.Get(pfeRef, "+++SrvID");
531  if (ent)
532  {SrvID.insert(ent->buf1.buf, 0, ent->buf1.len);
533  pfeRef.UnLock();
534  }
535  ent = cacheAdmin.Get(pfeRef, "+++SrvEmail");
536  if (ent)
537  SrvEmail.insert(ent->buf1.buf, 0, ent->buf1.len);
538  // Default error message
539  DefError += SrvEmail;
540  pfeRef.UnLock();
541  }
542  DEBUG("server ID: "<<SrvID);
543  DEBUG("contact e-mail: "<<SrvEmail);
544  }
545  }
546  } else if (UserPwd == 0 && !SysPwd) {
547  PRINT("no passwd info available - invalid ");
548  ErrF(erp,kPWErrError,"could not find a valid password file");
549  return Parms;
550  }
551  //
552  // Init cache for user pwd information
553  if (UserPwd > 0 || SysPwd) {
554  if (cacheUser.Init(100) != 0) {
555  PRINT("problems init cache for user pwd info"
556  " - passwd files in user accounts will not be used");
557  UserPwd = 0;
558  }
559  }
560 
561  //
562  // List of crypto modules
563  String cryptlist = opt.clist ? (const char *)(opt.clist) : DefCrypto;
564 
565  //
566  // Load crypto modules
567  XrdSutPFEntry ent;
568  XrdCryptoFactory *cf = 0;
569  String clist = cryptlist;
570  if (clist.length()) {
571  String ncpt = "";
572  int from = 0;
573  while ((from = clist.tokenize(ncpt, from, '|')) != -1) {
574  if (ncpt.length() > 0) {
575  // Try loading
576  if ((cf = XrdCryptoFactory::GetCryptoFactory(ncpt.c_str()))) {
577  // Add it to the list
578  cryptID[ncrypt] = cf->ID();
579  cryptName[ncrypt].insert(cf->Name(),0,strlen(cf->Name())+1);
580  cf->SetTrace(trace);
581  // Ref cipher
582  String ptag("+++SrvPuk_");
583  ptag += cf->ID();
584  if (FileAdmin.length() > 0) {
585  // Acquire the privileges, if needed
586  XrdSysPrivGuard priv(pw->pw_uid, pw->pw_gid);
587  if (priv.Valid()) {
588  if (PFAdmin.ReadEntry(ptag.c_str(),ent) <= 0) {
589  PRINT("ref cipher for module "<<ncpt<<" missing: disable");
590  cryptlist.erase(ncpt);
591  } else {
592  XrdSutBucket bck;
593  bck.SetBuf(ent.buf1.buf,ent.buf1.len);
594  if (!(refcip[ncrypt] = cf->Cipher(&bck))) {
595  PRINT("ref cipher for module "<<ncpt<<
596  " cannot be instantiated : disable");
597  cryptlist.erase(ncpt);
598  } else {
599  ncrypt++;
600  if (ncrypt >= XrdCryptoMax) {
601  PRINT("max number of crypto modules ("
602  << XrdCryptoMax <<") reached ");
603  break;
604  }
605  }
606  }
607  }
608  }
609  } else {
610  PRINT("cannot instantiate crypto factory "<<ncpt);
611  }
612  }
613  }
614  }
615 
616  //
617  // We need at least one valid crypto module
618  if (ncrypt <= 0) {
619  PRINT("could not find any valid crypto module");
620  ErrF(erp,kPWErrInit,"could not find any valid crypto module");
621  return Parms;
622  }
623 
624  //
625  // users' pwd information
626  if (UserPwd > 0) {
627  FileUser = ("/" + UserRef);
628  if (opt.udir) {
629  FileUser.insert(opt.udir,0);
630  if (FileUser[0] != '/') FileUser.insert('/',0);
631  } else {
632  // Use default $(HOME)/.<Prefix>
633  FileUser.insert(Prefix,0);
634  FileUser.insert("/.",0);
635  }
636  //
637  // Crypt-hash file name, if requested
638  if (opt.cpass) {
639  UserPwd = 2;
640  FileCrypt = opt.cpass;
641  if (FileCrypt[0] != '/') FileCrypt.insert('/',0);
642  }
643  }
644 
645  //
646  // Whether to save client creds
647  KeepCreds = (opt.keepcreds > -1) ? opt.keepcreds : KeepCreds;
648  if (KeepCreds > 0)
649  NOTIFY("Exporting client creds to internal buffer");
650 
651  //
652  // Whether to export client creds to a file
653  FileExpCreds = (opt.expcreds) ? opt.expcreds : FileExpCreds;
654  if (FileExpCreds.length() > 0) {
655  // Export format
656  FmtExpCreds = opt.expfmt;
657  const char *efmts[4] = {"PFile", "hex", "raw", "raw/nokeyword"};
658  NOTIFY("Exporting client creds (fmt:"<<efmts[FmtExpCreds]<<") to files "<<FileExpCreds);
659  }
660 
661  //
662  // Priority option field
663  String popt = "";
664  if (SysPwd) {
665  popt += "sys";
666  }
667 
668  //
669  // Parms in the form: &P=pwd,c:<cryptomod>,v:<version>,id:<srvid>
670  Parms = new char[cryptlist.length()+3+12+SrvID.length()+5+popt.length()+3];
671  if (Parms) {
672  if (popt.length() > 0)
673  sprintf(Parms,"v:%d,id:%s,c:%s,po:%s",
674  Version,SrvID.c_str(),cryptlist.c_str(),popt.c_str());
675  else
676  sprintf(Parms,"v:%d,id:%s,c:%s",
677  Version,SrvID.c_str(),cryptlist.c_str());
678  } else {
679  PRINT("no system resources for 'Parms'");
680  ErrF(erp,kPWErrInit,"no system resources for 'Parms'");
681  }
682 
683  // Some notification
684  NOTIFY("using FileAdmin: "<<FileAdmin);
685  NOTIFY("server ID: "<<SrvID);
686  NOTIFY("contact e-mail: "<<SrvEmail);
687  NOTIFY("auto-registration mode: "<<AutoReg);
688  NOTIFY("verify client mode: "<<VeriClnt);
689  NOTIFY("available crypto modules: "<<cryptlist);
690  if (UserPwd > 0) {
691  NOTIFY("using private pwd files: $(HOME)"<<FileUser);
692  if (UserPwd > 1) {
693  NOTIFY("using private crypt-hash files: $(HOME)"<<FileCrypt);
694  }
695  }
696  if (SysPwd) {
697  NOTIFY("using system pwd information");
698  }
699  if (KeepCreds) {
700  NOTIFY("client credentials will be kept");
701  }
702  }
703 
704  //
705  // Client specific options
706  if (!Server) {
707  //
708  // Server verification level
709  VeriSrv = (opt.verisrv > -1) ? opt.verisrv : VeriSrv;
710  //
711  // Server puks file
712  FileSrvPuk = "";
713  if (opt.srvpuk) {
714  FileSrvPuk = opt.srvpuk;
715  if (XrdSutExpand(FileSrvPuk) != 0) {
716  PRINT("cannot expand "<<opt.srvpuk);
717  FileSrvPuk = "";
718  }
719  }
720  //
721  // If not defined, use default
722  if (FileSrvPuk.length() <= 0 && infodir.length() > 0)
723  FileSrvPuk = infodir + SrvPukRef;
724 
725  if (FileSrvPuk.length() > 0) {
726  kXR_int32 openmode = 0;
727  struct stat st;
728  //
729  if (stat(FileSrvPuk.c_str(),&st) == -1) {
730  if (errno == ENOENT) {
731  PRINT("server public key file "<<FileSrvPuk<<" non existing: creating");
732  openmode = kPFEcreate;
733  // Make sure that the dir path exists
734  XrdOucString dir = FileSrvPuk;
735  dir.erase(dir.rfind('/')+1);
736  DEBUG("asserting dir: "<<dir);
737  if (XrdSutMkdir(dir.c_str(),0777) != 0) {
738  PRINT("cannot create dir for srvpuk(errno: "<<errno<<")");
739  ErrF(erp,kPWErrInit,"cannot create dir for server public key file- exit");
740  return Parms;
741  }
742  } else {
743  PRINT("cannot stat server public key file (errno: "<<errno<<")");
744  FileSrvPuk = "";
745  PRINT("server public key file invalid - exit");
746  ErrF(erp,kPWErrInit,"server public key file invalid - exit");
747  return Parms;
748  }
749  }
750  //
751  // Load server ID
752  PFSrvPuk.Init(FileSrvPuk.c_str(),openmode);
753  if (PFSrvPuk.IsValid()) {
754  //
755  // Init cache for server puk file
756  if (cacheSrvPuk.Load(FileSrvPuk.c_str()) != 0) {
757  PRINT("problems init cache for server public key file ");
758  ErrF(erp,kPWErrError,"initializing cache for server public key file ");
759  return Parms;
760  }
761  if (QTRACE(Authen)) { cacheSrvPuk.Dump(); }
762  } else {
763  PRINT("server public key file invalid ");
764  ErrF(erp,kPWErrInit,"server public key file invalid");
765  return Parms;
766  }
767  } else {
768  PRINT("server public key file undefined");
769  ErrF(erp,kPWErrInit,"server public key file undefined");
770  return Parms;
771  }
772 
773  //
774  // Whether to search for autologin information
775  AutoLogin = (opt.alog > -1) ? opt.alog : AutoLogin;
776  NOTIFY("AutoLogin level: "<<AutoLogin);
777  //
778  // Max number of re-prompts (for inconsistent inputs)
779  MaxPrompts = (opt.maxprompts > -1) ? opt.maxprompts : MaxPrompts;
780  //
781  // Attach autologin file name, if requested
782  if (AutoLogin > 0) {
783  bool filefound = 0;
784  String fnrc(256);
785  if (opt.alogfile) {
786  fnrc = opt.alogfile;
787  if (XrdSutExpand(fnrc) != 0) {
788  PRINT("cannot expand "<<opt.alogfile);
789  fnrc = "";
790  }
791  }
792  //
793  // If file name not specified ...
794  if (fnrc.length() <= 0)
795  // use default
796  fnrc = infodir + NetRcRef;
797 
798  if (fnrc.length() > 0) {
799  kXR_int32 openmode = 0;
800  struct stat st;
801  if (stat(fnrc.c_str(),&st) == -1) {
802  if (errno == ENOENT) {
803  PRINT("Autologin file "<<fnrc<<" non existing: creating");
804  openmode = kPFEcreate;
805  } else {
806  PRINT("cannot stat autologin file (errno: "<<errno<<")");
807  PRINT("switching off auto-login");
808  AutoLogin = 0;
809  }
810  }
811 
812  if (AutoLogin > 0) {
813  // Attach to file
814  PFAlog.Init(fnrc.c_str(),openmode);
815  if (PFAlog.IsValid()) {
816  // Init cache for autologin file
817  if (cacheAlog.Load(fnrc.c_str()) == 0) {
818  if (QTRACE(Authen)) { cacheAlog.Dump(); }
819  filefound =1;
820  } else {
821  PRINT("problems init cache for autologin file");
822  }
823  } else {
824  PRINT("problems attaching-to / creating autologin file");
825  }
826  }
827  }
828  //
829  // Notify if not found
830  if (!filefound) {
831  NOTIFY("could not init properly autologin - switch off ");
832  AutoLogin = 0;
833  }
834  }
835  //
836  // Notify if not found
837  if (AutoLogin <= 0) {
838  // Init anyhow cache to cache information during session
839  if (cacheAlog.Init(100) != 0) {
840  PRINT("problems init cache for user temporary autolog");
841  }
842  }
843  // We are done
844  Parms = (char *)"";
845  }
846 
847  // We are done
848  return Parms;
849 }
850 
851 /******************************************************************************/
852 /* D e l e t e */
853 /******************************************************************************/
855 {
856  // Deletes the protocol
857  if (Entity.host) free(Entity.host);
858  // Cleanup the handshake variables, if still there
859  SafeDelete(hs);
860  delete this;
861 }
862 
863 /******************************************************************************/
864 /* C l i e n t O r i e n t e d F u n c t i o n s */
865 /******************************************************************************/
866 /******************************************************************************/
867 /* g e t C r e d e n t i a l s */
868 /******************************************************************************/
869 
871  XrdOucErrInfo *ei)
872 {
873  // Query client for the password; remote username and host
874  // are specified in 'parm'. File '.rootnetrc' is checked.
875  EPNAME("getCredentials");
876 
877  // If we are a server the only reason to be here is to get the forwarded
878  // or saved client credentials
879  if (srvMode) {
880  XrdSecCredentials *creds = 0;
881  if (clientCreds) {
882  // Duplicate the buffer (otherwise it will get deleted ...)
883  int sz = clientCreds->size;
884  char *nbuf = (char *) malloc(sz);
885  if (nbuf) {
886  memcpy(nbuf, clientCreds->buffer, sz);
887  creds = new XrdSecCredentials(nbuf, sz);
888  }
889  }
890  return creds;
891  }
892 
893  // Handshake vars conatiner must be initialized at this point
894  if (!hs)
895  return ErrC(ei,0,0,0,kPWErrError,
896  "handshake var container missing","getCredentials");
897  hs->ErrMsg = "";
898 
899  //
900  // Nothing to do if buffer is empty and not filled during construction
901  if ((!parm && !hs->Parms) || (parm && (!(parm->buffer) || parm->size <= 0)))
902  return ErrC(ei,0,0,0,kPWErrNoBuffer,"missing parameters","getCredentials");
903 
904  // Count interations
905  (hs->Iter)++;
906 
907  // Update time stamp
908  hs->TimeStamp = time(0);
909 
910  // Local vars
911  int nextstep = 0;
912  const char *stepstr = 0;
913  kXR_int32 status = 0;
914  char *bpub = 0;
915  int lpub = 0;
916  String CryptList = "";
917  String Host = "";
918  String RemID = "";
919  String Emsg;
920  String specID = "";
921  // Buffer / Bucket related
922  XrdSutBucket *bck = 0;
923  XrdSutBuffer *bpar = 0; // Global buffer
924  XrdSutBuffer *bmai = 0; // Main buffer
925  // Session status
926  pwdStatus_t SessionSt;
927  memset(&SessionSt,0,sizeof(SessionSt));
928 
929  //
930  // Unlocks automatically returning
931  XrdSysMutexHelper pwdGuard(&pwdContext);
932  //
933  // Decode received buffer
934  bpar = hs->Parms;
935  if (!bpar && !(bpar = new XrdSutBuffer((const char *)parm->buffer,parm->size)))
936  return ErrC(ei,0,0,0,kPWErrDecodeBuffer,"global",stepstr);
937  // Ownership has been transferred
938  hs->Parms = 0;
939  //
940  // Check protocol ID name
941  if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
942  return ErrC(ei,bpar,bmai,0,kPWErrBadProtocol,stepstr);
943  //
944  // The step indicates what we are supposed to do
945  hs->Step = (bpar->GetStep()) ? bpar->GetStep() : kXPS_init;
946  stepstr = ServerStepStr(hs->Step);
947  // Dump, if requested
948  if (QTRACE(Dump)) {
949  bpar->Dump(stepstr);
950  }
951  //
952  // Find first crypto module to be used
953  if (ParseCrypto(bpar) != 0)
954  return ErrC(ei,bpar,0,0,kPWErrLoadCrypto,stepstr);
955  //
956  // Parse input buffer
957  if (ParseClientInput(bpar, &bmai, Emsg) == -1) {
958  PRINT(Emsg);
959  return ErrC(ei,bpar,bmai,0,kPWErrParseBuffer,Emsg.c_str(),stepstr);
960  }
961  //
962  // Version
963  DEBUG("version run by server: "<< hs->RemVers);
964  //
965  // Dump what we got
966  if (QTRACE(Dump)) {
967  bmai->Dump("Main IN");
968  }
969  //
970  // Print server messages, if any
971  if (hs->Iter > 1) {
972  bmai->Message();
973  bmai->Deactivate(kXRS_message);
974  }
975  //
976  // Check random challenge
977  if (!CheckRtag(bmai, Emsg))
978  return ErrC(ei,bpar,bmai,0,kPWErrBadRndmTag,Emsg.c_str(),stepstr);
979 
980  //
981  // Get the status bucket, if any
982  if ((bck = bmai->GetBucket(kXRS_status))) {
983  int pst = 0;
984  memcpy(&pst,bck->buffer,sizeof(pwdStatus_t));
985  pst = ntohl(pst);
986  memcpy(&SessionSt, &pst, sizeof(pwdStatus_t));
987  bmai->Deactivate(kXRS_status);
988  } else {
989  SessionSt.ctype = kpCT_normal;
990  }
991  //
992  // Now action depens on the step
993  nextstep = kXPC_none;
994  switch (hs->Step) {
995 
996  case kXPS_init: // The following 3 cases may fall through
997  case kXPS_puk:
998  case kXPS_signedrtag: // (after kXRC_verifysrv)
999 if (hs->Step == kXPS_init)
1000  {
1001  //
1002  // Add bucket with cryptomod to the global list
1003  // (This must be always visible from now on)
1004  if (bpar->AddBucket(hs->CryptoMod,kXRS_cryptomod) != 0)
1005  return ErrC(ei,bpar,bmai,0,
1007  //
1008  // Add bucket with our version to the main list
1009  if (bmai->MarshalBucket(kXRS_version,(kXR_int32)(Version)) != 0)
1010  return ErrC(ei,bpar,bmai,0, kPWErrCreateBucket,
1011  XrdSutBuckStr(kXRS_version),"(main list)",stepstr);
1012  //
1013  // We set some options in the option field of a pwdStatus_t structure
1014  if (hs->Tty || (AutoLogin > 0))
1015  SessionSt.options = kOptsClntTty;
1016  }
1017 // case kXPS_puk:
1018 if ((hs->Step == kXPS_init) || (hs->Step == kXPS_puk))
1019  {
1020  // After auto-reg request, server puk have been saved in ParseClientInput:
1021  // we need to start a full normal login now
1022 
1023  //
1024  // If we have a session cipher we extract the public part
1025  // and add to the main packet for transmission to server
1026  if (hs->Hcip) {
1027  //
1028  // Extract buffer with public info for the cipher agreement
1029  if (!(bpub = hs->Hcip->Public(lpub)))
1030  return ErrC(ei,bpar,bmai,0,
1031  kPWErrNoPublic,"session",stepstr);
1032  //
1033  // Add it to the global list
1034  if (bpar->UpdateBucket(bpub,lpub,kXRS_puk) != 0)
1035  return ErrC(ei,bpar,bmai,0, kPWErrAddBucket,
1036  XrdSutBuckStr(kXRS_puk),"global",stepstr);
1037  SafeDelArray(bpub);
1038  //
1039  // If we are requiring server verification of puk ownership
1040  // we are done for this step
1041  if (VeriSrv == 1) {
1042  nextstep = kXPC_verifysrv;
1043  break;
1044  }
1045  }
1046  }
1047 // case kXPS_signedrtag: // (after kXRC_verifysrv)
1048  //
1049  // Add the username
1050  if (hs->User.length()) {
1051  if (bmai->AddBucket(hs->User,kXRS_user) != 0)
1052  return ErrC(ei,bpar,bmai,0, kPWErrDuplicateBucket,
1053  XrdSutBuckStr(kXRS_user),stepstr);
1054  } else
1055  return ErrC(ei,bpar,bmai,0, kPWErrNoUser,stepstr);
1056 
1057  //
1058  // If we do not have a session cipher, the only thing we can
1059  // try is auto-registration
1060  if (!(hs->Hcip)) {
1061  nextstep = kXPC_autoreg;
1062  break;
1063  }
1064 
1065  //
1066  // Normal attempt: add credentials
1067  status = kpCT_normal;
1068  if (hs->SysPwd == 1)
1069  status = kpCT_crypt;
1070  if (hs->SysPwd == 2)
1071  status = kpCT_afs;
1072  if (!(bck = QueryCreds(bmai, (AutoLogin > 0), status)))
1073  return ErrC(ei,bpar,bmai,0, kPWErrQueryCreds,
1074  hs->Tag.c_str(),stepstr);
1075  bmai->AddBucket(bck);
1076  //
1077  // Tell the server we want to change the password, if so
1078  if (hs->Pent->status == kPFE_onetime)
1079  SessionSt.options |= kOptsChngPwd;
1080  //
1081  nextstep = kXPC_normal;
1082  break;
1083 
1084  case kXPS_credsreq:
1085  //
1086  // If this is not the first time, during the handshake, that
1087  // we query credentials, any save buffer must insufficient,
1088  // so invalidate it
1089  if (hs->Pent)
1090  hs->Pent->cnt = 1;
1091  //
1092  // Server requires additional credentials: the status bucket
1093  // tells us what she wants exactly
1094  status = SessionSt.ctype;
1095  if (!(bck = QueryCreds(bmai, 0, status)))
1096  return ErrC(ei,bpar,bmai,0, kPWErrQueryCreds,
1097  hs->Tag.c_str(),stepstr);
1098  bmai->AddBucket(bck);
1099  //
1100  nextstep = kXPC_creds;
1101  break;
1102 
1103  case kXPS_failure:
1104  //
1105  // Failure: invalidate cache
1106  hs->Pent->buf1.SetBuf();
1107  hs->Pent->buf2.SetBuf();
1108  //
1109  nextstep = kXPC_failureack;
1110  break;
1111 
1112  case kXPS_newpuk:
1113  //
1114  // New server puk have been saved in ParseClientInput: we
1115  // just need to sign the random tag
1116  case kXPS_rtag:
1117  //
1118  // Not much to do: the random tag is signed in AddSerialized
1119  nextstep = kXPC_signedrtag;
1120  break;
1121 
1122  default:
1123  return ErrC(ei,bpar,bmai,0, kPWErrBadOpt,stepstr);
1124  }
1125  //
1126  // Add / Update status
1127  int *pst = (int *) new char[sizeof(pwdStatus_t)];
1128  memcpy(pst,&SessionSt,sizeof(pwdStatus_t));
1129  *pst = htonl(*pst);
1130  if (bmai->AddBucket((char *)pst,sizeof(pwdStatus_t), kXRS_status) != 0) {
1131  PRINT("problems adding bucket kXRS_status");
1132  }
1133  //
1134  // Serialize and encrypt
1135  if (AddSerialized('c', nextstep, hs->ID,
1136  bpar, bmai, kXRS_main, hs->Hcip) != 0)
1137  return ErrC(ei,bpar,bmai,0,
1138  kPWErrSerialBuffer,"main",stepstr);
1139  //
1140  // Serialize the global buffer
1141  char *bser = 0;
1142  int nser = bpar->Serialized(&bser,'f');
1143 
1144  if (QTRACE(Dump)) {
1145  bpar->Dump(ClientStepStr(bpar->GetStep()));
1146  bmai->Dump("Main OUT");
1147  }
1148  //
1149  // We may release the buffers now
1150  REL2(bpar,bmai);
1151  //
1152  // Return serialized buffer
1153  if (nser > 0) {
1154  DEBUG("returned " << nser <<" bytes of credentials");
1155  return new XrdSecCredentials(bser, nser);
1156  } else {
1157  DEBUG("problems with final serialization");
1158  return (XrdSecCredentials *)0;
1159  }
1160 }
1161 
1162 /******************************************************************************/
1163 /* S e r v e r O r i e n t e d M e t h o d s */
1164 /******************************************************************************/
1165 /******************************************************************************/
1166 /* A u t h e n t i c a t e */
1167 /******************************************************************************/
1168 
1170  XrdSecParameters **parms,
1171  XrdOucErrInfo *ei)
1172 {
1173  //
1174  // Check if we have any credentials or if no credentials really needed.
1175  // In either case, use host name as client name
1176  EPNAME("Authenticate");
1177 
1178  //
1179  // If cred buffer is two small or empty assume host protocol
1180  if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer) {
1181  strncpy(Entity.prot, "host", sizeof(Entity.prot));
1182  return 0;
1183  }
1184 
1185  // Handshake vars container must be initialized at this point
1186  if (!hs)
1187  return ErrS(String("none"),ei,0,0,0,kPWErrError,
1188  "handshake var container missing",
1189  "protocol initialization problems");
1190  hs->ErrMsg = "";
1191  //
1192  // Update time stamp
1193  hs->TimeStamp = time(0);
1194 
1195  //
1196  // ID of this handshaking
1197  hs->ID = Entity.tident;
1198  DEBUG("handshaking ID: " << hs->ID);
1199 
1200  // Local vars
1201  int i = 0;
1202  int kS_rc = kpST_more;
1203  int rc = 0;
1204  int entst = 0;
1205  int nextstep = 0;
1206  int ctype = kpCT_normal;
1207  char *bpub = 0, *bpid = 0;
1208  int lpub = 0;
1209  const char *stepstr = 0;
1210  String Message;
1211  String CryptList;
1212  String Host;
1213  String SrvPuKExp;
1214  String Salt;
1215  String RndmTag;
1216  String ClntMsg(256);
1217  // Buffer related
1218  XrdSutBuffer *bpar = 0; // Global buffer
1219  XrdSutBuffer *bmai = 0; // Main buffer
1220  XrdSutBucket *bck = 0; // Generic bucket
1221  // The local status info
1222  pwdStatus_t SessionSt = { 0, 0, 0};
1223 
1224  //
1225  // Unlocks automatically returning
1226  XrdSysMutexHelper pwdGuard(&pwdContext);
1227  //
1228  // Decode received buffer
1229  if (!(bpar = new XrdSutBuffer((const char *)cred->buffer,cred->size)))
1230  return ErrS(hs->ID,ei,0,0,0,kPWErrDecodeBuffer,"global",stepstr);
1231  //
1232  // Check protocol ID name
1233  if (strcmp(bpar->GetProtocol(),XrdSecPROTOIDENT))
1234  return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadProtocol,stepstr);
1235  //
1236  // The step indicates what we are supposed to do
1237  hs->Step = bpar->GetStep();
1238  stepstr = ClientStepStr(hs->Step);
1239  // Dump, if requested
1240  if (QTRACE(Dump)) {
1241  bpar->Dump(stepstr);
1242  }
1243 
1244  //
1245  // Find first crypto module to be used
1246  if (ParseCrypto(bpar) != 0)
1247  return ErrS(hs->ID,ei,bpar,0,0,kPWErrLoadCrypto,stepstr);
1248  //
1249  // Parse input buffer
1250  if (ParseServerInput(bpar, &bmai, ClntMsg) == -1) {
1251  PRINT(ClntMsg);
1252  return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrParseBuffer,ClntMsg.c_str(),stepstr);
1253  }
1254  //
1255  // Get handshake status
1256  if ((bck = bmai->GetBucket(kXRS_status))) {
1257  int pst = 0;
1258  memcpy(&pst,bck->buffer,sizeof(pwdStatus_t));
1259  pst = ntohl(pst);
1260  memcpy(&SessionSt, &pst, sizeof(pwdStatus_t));
1261  bmai->Deactivate(kXRS_status);
1262  } else {
1263  NOTIFY("no bucket kXRS_status found in main buffer");
1264  }
1265  hs->Tty = SessionSt.options & kOptsClntTty;
1266  //
1267  // Client name
1268  unsigned int ulen = hs->User.length();
1269  ulen = (ulen > sizeof(CName)-1) ? sizeof(CName)-1 : ulen;
1270  if (ulen)
1271  strcpy(CName, hs->User.c_str());
1272  // And set link to entity
1273  Entity.name = strdup(CName);
1274 
1275  //
1276  // Version
1277  DEBUG("version run by client: "<< hs->RemVers);
1278  //
1279  // Dump, if requested
1280  if (QTRACE(Dump)) {
1281  bmai->Dump("main IN");
1282  }
1283  //
1284  // Check random challenge
1285  if (!CheckRtag(bmai, ClntMsg))
1286  return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadRndmTag,stepstr,ClntMsg.c_str());
1287  //
1288  // Check also host / time stamp (it will be done only if really neede)
1289  if (!CheckTimeStamp(bmai, TimeSkew, ClntMsg))
1290  return ErrS(hs->ID,ei,bpar,bmai,0,kPWErrBadRndmTag,stepstr,ClntMsg.c_str());
1291  //
1292  // Now action depens on the step
1293  bool savecreds = (SessionSt.options & kOptsExpCred);
1294  switch (hs->Step) {
1295 
1296  case kXPC_verifysrv:
1297  //
1298  // Client required us to sign a random challenge: this is done
1299  // in AddSerialized, so nothing to do here
1300  nextstep = kXPS_signedrtag;
1301  break;
1302 
1303  case kXPC_signedrtag:
1304  //
1305  // Client signed the random challenge we sent: if we are here,
1306  // everything was fine
1307  kS_rc = kpST_ok;
1308  nextstep = kXPS_none;
1309  break;
1310 
1311  case kXPC_failureack:
1312  //
1313  // Client acknowledged failure
1314  kS_rc = kpST_error;
1315  nextstep = kXPS_none;
1316  break;
1317 
1318  case kXPC_autoreg:
1319  //
1320  // Client has lost the key or requested auto-registration: we
1321  // check the username: if it has a good entry or it is allowed
1322  // to auto-register (the check is done in QueryUser) we send
1323  // the public part of the key; otherwise we fail
1324  rc = QueryUser(entst, ClntMsg);
1325  if (rc < 0 || (entst == kPFE_disabled))
1326  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
1327  DefError.c_str(),stepstr);
1328  //
1329  // We have to send the public key
1330  for (i = 0; i < ncrypt; i++) {
1331  if (refcip[i]) {
1332  //
1333  // Extract buffer with public info for the cipher agreement
1334  if (!(bpub = refcip[i]->Public(lpub)))
1335  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrNoPublic,
1336  "session",stepstr);
1337  bpid = new char[lpub+5];
1338  if (bpid) {
1339  char cid[5] = {0};
1340  sprintf(cid,"%d",cryptID[i]);
1341  memcpy(bpid,cid,5);
1342  memcpy(bpid+5, bpub, lpub);
1343  //
1344  // Add it to the global list
1345  if (bmai->AddBucket(bpid,lpub+5,kXRS_puk) != 0)
1346  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrAddBucket,
1347  "main",stepstr);
1348  } else
1349  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrError,
1350  "out-of-memory",stepstr);
1351  SafeDelArray(bpub); // bpid is taken by the bucket
1352  }
1353  }
1354  // client should now go through a complete login
1355  nextstep = kXPS_puk;
1356  break;
1357 
1358  case kXPC_normal:
1359  case kXPC_creds:
1360 if (hs->Step == kXPC_normal)
1361  {
1362  //
1363  // Complete login sequence: check user and creds
1364  if (QueryUser(entst,ClntMsg) != 0)
1365  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
1366  ": user ",hs->User.c_str(),stepstr);
1367  // Nothing to do, if disabled
1368  if (entst == kPFE_disabled)
1369  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadCreds,
1370  ": user ",hs->User.c_str(),stepstr);
1371 
1372  if (entst == kPFE_expired || entst == kPFE_onetime) {
1373  // New credentials should asked upon success first check
1374  SessionSt.options |= kOptsExpCred;
1375  }
1376  if (entst == kPFE_crypt) {
1377  // User credentials are either in crypt form (private or
1378  // system ones) or of AFS type; in case of failure
1379  // this flag allows the client to send the right creds
1380  // at next iteration
1381  if (ClntMsg.beginswith("afs:")) {
1382  SessionSt.options |= kOptsAFSPwd;
1383  } else
1384  SessionSt.options |= kOptsCrypPwd;
1385  // Reset the message
1386  ClntMsg = "";
1387  }
1388  // Creds, if any, should be checked, unles we allow auto-registration
1389  savecreds = (entst != kPFE_allowed) ? 0 : 1;
1390  }
1391 
1392 // case kXPC_creds: (falls into here from _normal)
1393  //
1394  // Final login sequence: extract and check creds
1395  // Extract credentials from main buffer
1396  if (!(bck = bmai->GetBucket(kXRS_creds))) {
1397  //
1398  // If credentials are missing, require them
1399  kS_rc = kpST_more;
1400  nextstep = kXPS_credsreq;
1401  break;
1402  }
1403  //
1404  // If we required new credentials at previous step, just save them
1405  if (savecreds) {
1406  if (SaveCreds(bck) != 0) {
1407  ClntMsg = "Warning: could not correctly update credentials database";
1408  }
1409  kS_rc = kpST_ok;
1410  nextstep = kXPS_none;
1411  bmai->Deactivate(kXRS_creds);
1412  break;
1413  }
1414  //
1415  // Credential type
1416  ctype = kpCT_normal;
1417  if (SessionSt.options & kOptsCrypPwd)
1418  ctype = kpCT_crypt;
1419  else if (SessionSt.options & kOptsAFSPwd) {
1420  ctype = kpCT_afs;
1421  String afsInfo;
1422  XrdSutBucket *bafs = bmai->GetBucket(kXRS_afsinfo);
1423  if (bafs)
1424  bafs->ToString(afsInfo);
1425  if (afsInfo == "c")
1426  ctype = kpCT_afsenc;
1427  }
1428  //
1429  // Check credentials
1430  if (!CheckCreds(bck, ctype)) {
1431  //
1432  // Count temporary failures
1433  (hs->Cref->cnt)++;
1434  // Reset expired credentials flag
1435  SessionSt.options &= ~kOptsExpCred;
1436  // Repeat if not too many attempts
1437  ClntMsg = DefError;
1438  if (hs->Cref->cnt < MaxPrompts) {
1439  // Set next step to credential request
1440  nextstep = kXPS_credsreq;
1441  kS_rc = kpST_more;
1442  // request again creds
1443  if (hs->Pent->status == kPFE_crypt) {
1444  SessionSt.ctype = kpCT_crypt;
1445  if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
1446  SessionSt.ctype = kpCT_afs;
1447  String afsinfo = hs->ErrMsg;
1448  bmai->UpdateBucket(afsinfo, kXRS_afsinfo);
1449  }
1450  ClntMsg = "";
1451  } else {
1452  SessionSt.ctype = kpCT_normal;
1453  ClntMsg = "insufficient credentials";
1454  }
1455  } else {
1456  // We communicate failure
1457  kS_rc = kpST_more;
1458  nextstep = kXPS_failure;
1459  // Count failures
1460  (hs->Pent->cnt)++;
1461  // Count failures
1462  hs->Pent->mtime = (kXR_int32)time(0);
1463  // Flush cache content to source file
1464  XrdSysPrivGuard priv(getuid(), getgid());
1465  if (priv.Valid()) {
1466  if (cacheAdmin.Flush() != 0) {
1467  PRINT("WARNING: some problem flushing to admin"
1468  " file after updating "<<hs->Pent->name);
1469  }
1470  }
1471  }
1472  } else {
1473  // Reset counter for temporary failures
1474  hs->Cref->cnt = 0;
1475  // Reset counter in file if needed
1476  if (hs->Pent->cnt > 0) {
1477  hs->Pent->cnt = 0;
1478  // Count failures
1479  hs->Pent->mtime = (kXR_int32)time(0);
1480  // Flush cache content to source file
1481  XrdSysPrivGuard priv(getuid(), getgid());
1482  if (priv.Valid()) {
1483  if (cacheAdmin.Flush() != 0) {
1484  PRINT("WARNING: some problem flushing to admin"
1485  " file after updating "<<hs->Pent->name);
1486  }
1487  }
1488  }
1489  kS_rc = kpST_ok;
1490  nextstep = kXPS_none;
1491  if (SessionSt.options & kOptsExpCred ||
1492  // Client requested a pwd change
1493  SessionSt.options & kOptsChngPwd) {
1494  kS_rc = kpST_more;
1495  nextstep = kXPS_credsreq;
1496  if (SessionSt.options & kOptsExpCred) {
1497  ClntMsg = "Credentials expired";
1498  } else if (SessionSt.options & kOptsChngPwd) {
1499  ClntMsg = "Password change requested";
1500  }
1501  // request new creds
1502  SessionSt.ctype = kpCT_new;
1503  // So we can save at next round
1504  SessionSt.options |= kOptsExpCred;
1505  }
1506  // Create buffer to keep the credentials, if required
1507  if (KeepCreds) {
1508  int sz = bck->size+5;
1509  char *buf = (char *) malloc(sz);
1510  if (buf) {
1511  memcpy(buf, "&pwd", 4);
1512  buf[4] = 0;
1513  memcpy(buf+5, bck->buffer, bck->size);
1514  // Put in hex
1515  char *out = new char[2*sz+1];
1516  XrdSutToHex(buf, sz, out);
1517  // Cleanup any existing info
1518  SafeDelete(clientCreds);
1519  clientCreds = new XrdSecCredentials(out, 2*sz+1);
1520  }
1521  }
1522  // Export creds to a file, if required
1523  if (FileExpCreds.length() > 0) {
1524  if (ExportCreds(bck) != 0)
1525  PRINT("WARNING: some problem exporting creds to file;"
1526  " template is :"<<FileExpCreds);
1527  }
1528  }
1529  // We will not use again these credentials
1530  bmai->Deactivate(kXRS_creds);
1531 
1532  break;
1533 
1534  default:
1535  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrBadOpt, stepstr);
1536  }
1537 
1538  //
1539  // If strong signature checking is required add random tag
1540  if (kS_rc == kpST_ok) {
1541  if (VeriClnt == 2 && !(hs->RtagOK)) {
1542  // Send only the random tag to sign
1543  nextstep = kXPS_rtag;
1544  kS_rc = kpST_more;
1545  }
1546  }
1547 
1548  //
1549  // If we need additional info but the client caa not reply, just fail
1550  if (kS_rc == kpST_more && !(hs->Tty)) {
1551  PRINT("client cannot reply to additional request: failure");
1552  // Deactivate everything
1553  bpar->Deactivate(-1);
1554  bmai->Deactivate(-1);
1555  kS_rc = kpST_error;
1556  }
1557  //
1558  if (kS_rc == kpST_more) {
1559  //
1560  // Add message to client
1561  if (ClntMsg.length() > 0)
1562  if (bmai->AddBucket(ClntMsg,kXRS_message) != 0) {
1563  PRINT("problems adding bucket with message for client");
1564  }
1565  //
1566  // We set some options in the option field of a pwdStatus_t structure
1567  int *pst = (int *) new char[sizeof(pwdStatus_t)];
1568  memcpy(pst,&SessionSt,sizeof(pwdStatus_t));
1569  *pst = htonl(*pst);
1570  if (bmai->AddBucket((char *)pst,sizeof(pwdStatus_t), kXRS_status) != 0) {
1571  PRINT("problems adding bucket kXRS_status");
1572  }
1573  //
1574  // Serialize, encrypt and add to the global list
1575  if (AddSerialized('s', nextstep, hs->ID,
1576  bpar, bmai, kXRS_main, hs->Hcip) != 0)
1577  return ErrS(hs->ID,ei,bpar,bmai,0, kPWErrSerialBuffer,
1578  "main / session cipher",stepstr);
1579  //
1580  // Serialize the global buffer
1581  char *bser = 0;
1582  int nser = bpar->Serialized(&bser,'f');
1583  //
1584  // Dump, if requested
1585  if (QTRACE(Dump)) {
1586  bpar->Dump(ServerStepStr(bpar->GetStep()));
1587  bmai->Dump("Main OUT");
1588  }
1589  //
1590  // Create buffer for client
1591  *parms = new XrdSecParameters(bser,nser);
1592  } else {
1593  //
1594  // Cleanup handshake vars
1595  SafeDelete(hs);
1596  }
1597  //
1598  // We may release the buffers now
1599  REL2(bpar,bmai);
1600  //
1601  // All done
1602  return kS_rc;
1603 }
1604 
1605 /******************************************************************************/
1606 /* E n a b l e T r a c i n g */
1607 /******************************************************************************/
1608 
1610 {
1611  // Initiate error logging and tracing
1612 
1613  eDest.logger(&Logger);
1614  PWDTrace = new XrdOucTrace(&eDest);
1615  return PWDTrace;
1616 }
1617 
1618 /******************************************************************************/
1619 /* p w d O p t i o n s :: P r i n t */
1620 /******************************************************************************/
1621 
1623 {
1624  // Dump summary of GSI init options
1625  EPNAME("InitOpts");
1626 
1627  // For clients print only if really required (for servers we notified it
1628  // always once for all)
1629  if ((mode == 'c') && debug <= 0) return;
1630 
1631  POPTS(t, "*** ------------------------------------------------------------ ***");
1632  POPTS(t, " Mode: "<< ((mode == 'c') ? "client" : "server"));
1633  POPTS(t, " Debug: "<< debug);
1634  if (mode == 'c') {
1635  POPTS(t, " Check user's autologin info: " << (alog != 0 ? "yes" : "no"));
1636  POPTS(t, " Verification level of server ownership on public key: " << verisrv);
1637  POPTS(t, " Max number of empty prompts:" << maxprompts);
1638  if (alogfile)
1639  POPTS(t, " Autologin file:" << alogfile);
1640  if (srvpuk)
1641  POPTS(t, " File with known servers public keys:" << srvpuk);
1642  POPTS(t, " Update auto-login info option:" << areg);
1643  } else {
1644  POPTS(t, " Check pwd file in user's home: " << (upwd != 0 ? "yes" : "no"));
1645  POPTS(t, " Verification level of client ownership on public key: " << vericlnt);
1646  POPTS(t, " Autoregistration option:" << areg);
1647  POPTS(t, " Check system pwd file option: " << syspwd);
1648  POPTS(t, " Credentials lifetime (seconds): " << lifecreds);
1649  POPTS(t, " Max number of failures: " << maxfailures);
1650  if (clist)
1651  POPTS(t, " List of supported crypto modules: " << clist);
1652  if (dir)
1653  POPTS(t, " Directory with admin pwd files: " << dir);
1654  if (udir)
1655  POPTS(t, " User's sub-directory with pwd files: " << udir);
1656  if (cpass)
1657  POPTS(t, " User's crypt hash pwd file: " << cpass);
1658  POPTS(t, " Keep client credentials in memory: " << (keepcreds != 0 ? "yes" : "no"));
1659  if (expcreds) {
1660  POPTS(t, " File for exported client credentials: " << expcreds);
1661  POPTS(t, " Format for exported client credentials: " << expfmt);
1662  } else {
1663  POPTS(t, " Client credentials not exported to file");
1664  }
1665  }
1666  POPTS(t, "*** ------------------------------------------------------------ ***");
1667 }
1668 
1669 /******************************************************************************/
1670 /* X r d S e c P r o t o c o l p w d I n i t */
1671 /******************************************************************************/
1672 
1674 
1675 extern "C"
1676 {
1677 char *XrdSecProtocolpwdInit(const char mode,
1678  const char *parms, XrdOucErrInfo *erp)
1679 {
1680  // One-time protocol initialization, filling the static flags and options
1681  // of the protocol.
1682  // For clients (mode == 'c') we use values in envs.
1683  // For servers (mode == 's') the command line options are passed through
1684  // parms.
1685  EPNAME("ProtocolpwdInit");
1686 
1687  pwdOptions opts;
1688  char *rc = (char *)"";
1689  char *cenv = 0;
1690 
1691  // Initiate error logging and tracing
1693 
1694  //
1695  // Clients first
1696  if (mode == 'c') {
1697  //
1698  // Decode envs:
1699  // "XrdSecDEBUG" debug flag ("0","1","2","3")
1700  // "XrdSecPWDVERIFYSRV" "1" server verification ON [default]
1701  // "0" server verification OFF
1702  // "XrdSecPWDSRVPUK" full path to file with server puks
1703  // [default: $HOME/.xrd/pwdsrvpuk]
1704  // "XrdSecPWDAUTOLOG" "1" autologin ON [default]
1705  // "0" autologin OFF
1706  // "XrdSecPWDALOGFILE" full path to file with autologin
1707  // info [default: $HOME/.xrd/pwdnetrc]
1708  // "XrdSecPWDALOGUPDT" update autologin file option:
1709  // "0" never [default]
1710  // "1" remove_obsolete_info
1711  // "2" "1" + register_new_valid_info
1712  // "XrdSecPWDMAXPROMPT" max number of attemts to get valid
1713  // input info by prompting the client
1714  //
1715  opts.mode = mode;
1716  // debug
1717  cenv = getenv("XrdSecDEBUG");
1718  if (cenv)
1719  {if (cenv[0] >= 49 && cenv[0] <= 51) opts.debug = atoi(cenv);
1720  else {PRINT("unsupported debug value from env XrdSecDEBUG: "<<cenv<<" - setting to 1");
1721  opts.debug = 1;
1722  }
1723  }
1724 
1725  // server verification
1726  cenv = getenv("XrdSecPWDVERIFYSRV");
1727  if (cenv)
1728  if (cenv[0] >= 48 && cenv[0] <= 49) opts.verisrv = atoi(cenv);
1729  // file with server public keys
1730  cenv = getenv("XrdSecPWDSRVPUK");
1731  if (cenv)
1732  opts.srvpuk = strdup(cenv);
1733  // autologin
1734  cenv = getenv("XrdSecPWDAUTOLOG");
1735  if (cenv)
1736  if (cenv[0] >= 48 && cenv[0] <= 50) opts.alog = atoi(cenv);
1737  // autologin file
1738  cenv = getenv("XrdSecPWDALOGFILE");
1739  if (cenv)
1740  opts.alogfile = strdup(cenv);
1741  // max re-prompts
1742  cenv = getenv("XrdSecPWDMAXPROMPT");
1743  if (cenv) {
1744  opts.maxprompts = strtol(cenv, (char **)0, 10);
1745  if (errno == ERANGE) opts.maxprompts = -1;
1746  }
1747  //
1748  // Setup the object with the chosen options
1749  rc = XrdSecProtocolpwd::Init(opts,erp);
1750 
1751  // Notify init options, if required or in case of init errors
1752  if (!rc) opts.debug = 1;
1753  opts.Print(pwdTrace);
1754 
1755  // Some cleanup
1756  if (opts.srvpuk) free(opts.srvpuk);
1757  if (opts.alogfile) free(opts.alogfile);
1758 
1759  // We are done
1760  return rc;
1761  }
1762 
1763  // Take into account xrootd debug flag
1764  cenv = getenv("XRDDEBUG");
1765  if (cenv && !strcmp(cenv,"1")) opts.debug = 1;
1766 
1767  //
1768  // Server initialization
1769  if (parms) {
1770  //
1771  // Duplicate the parms
1772  char parmbuff[1024];
1773  strlcpy(parmbuff, parms, sizeof(parmbuff));
1774  //
1775  // The tokenizer
1776  XrdOucTokenizer inParms(parmbuff);
1777 
1778  //
1779  // Decode parms:
1780  // for servers: [-upwd:<user_pwd_option>]
1781  // [-a:<autoreg_level>]
1782  // [-vc:<client_verification_level>]
1783  // [-dir:<dir_with_pwd_info>]
1784  // [-udir:<sub_dir_with_user_pwd_info>]
1785  // [-c:[-]ssl[:[-]<CryptoModuleName]]
1786  // [-d:<debug_level>]
1787  // [-syspwd]
1788  // [-lf:<credential_lifetime>]
1789  // [-maxfail:<max_number_of_failures>]
1790  // [-keepcreds]
1791  // [-expcreds:<creds_file_name>]
1792  // [-expfmt:<creds_exp_format>]
1793  //
1794  // <user_pwd_opt> = 0 (do-not-use), 1 (use), 2 (also-crypt-hash)
1795  // <debug_level> = 0 (none), 1 (low), 2 (medium), 3 (high) [0]
1796  // <autoreg_level> = 0 (none), 1 (local users + allowed tags), 2 (all) [0]
1797  // <credential_lifetime> = 1d, 5h:10m, ... (see XrdSutAux::ParseTime)
1798  // <client_verification_level> = 0 (none), 1 (timestamp), 2 (random tag) [2]
1799  // <creds_file_name> = can be a fully specified path or in the templated form
1800  // /path/<user>/file, with <user> expanded at the moment
1801  // of use with the login name.
1802  // <creds_exp_format> = 0 (XrdSutPFEntry in dedicated file),
1803  // 1 (hex form), 2 (plain), 3 (plain, no keywords) [0]
1804  //
1805  int debug = -1;
1806  int areg = -1;
1807  int vc = -1;
1808  int upw = -1;
1809  int syspwd = -1;
1810  int lifetime = -1;
1811  int maxfail = -1;
1812  String dir = "";
1813  String udir = "";
1814  String clist = "";
1815  String cpass = "";
1816  int keepcreds = -1;
1817  String expcreds = "";
1818  int expfmt = 0;
1819  char *op = 0;
1820  while (inParms.GetLine()) {
1821  while ((op = inParms.GetToken())) {
1822  if (!strncmp(op, "-upwd:",6)) {
1823  upw = atoi(op+6);
1824  } else if (!strncmp(op, "-dir:",5)) {
1825  dir = (const char *)(op+5);
1826  } else if (!strncmp(op, "-udir:",6)) {
1827  udir = (const char *)(op+6);
1828  } else if (!strncmp(op, "-c:",3)) {
1829  clist = (const char *)(op+3);
1830  } else if (!strncmp(op, "-d:",3)) {
1831  debug = atoi(op+3);
1832  } else if (!strncmp(op, "-a:",3)) {
1833  areg = atoi(op+3);
1834  } else if (!strncmp(op, "-vc:",4)) {
1835  vc = atoi(op+4);
1836  } else if (!strncmp(op, "-syspwd",7)) {
1837  syspwd = 1;
1838  } else if (!strncmp(op, "-lf:",4)) {
1839  lifetime = XrdSutParseTime(op+4);
1840  } else if (!strncmp(op, "-maxfail:",9)) {
1841  maxfail = atoi(op+9);
1842  } else if (!strncmp(op, "-cryptfile:",11)) {
1843  cpass = (const char *)(op+11);
1844  } else if (!strncmp(op, "-keepcreds",10)) {
1845  keepcreds = 1;
1846  } else if (!strncmp(op, "-expcreds:",10)) {
1847  expcreds = (const char *)(op+10);
1848  } else if (!strncmp(op, "-expfmt:",8)) {
1849  expfmt = atoi(op+8);
1850  }
1851  }
1852  // Check inputs
1853  areg = (areg >= 0 && areg <= 2) ? areg : 0;
1854  vc = (vc >= 0 && vc <= 2) ? vc : 2;
1855  }
1856 
1857  //
1858  // Build the option object
1859  opts.debug = (debug > -1) ? debug : opts.debug;
1860  opts.mode = 's';
1861  opts.areg = areg;
1862  opts.vericlnt = vc;
1863  opts.upwd = upw;
1864  opts.syspwd = syspwd;
1865  opts.lifecreds = lifetime;
1866  opts.maxfailures = maxfail;
1867  opts.expfmt = expfmt;
1868  if (dir.length() > 0)
1869  opts.dir = (char *)dir.c_str();
1870  if (udir.length() > 0)
1871  opts.udir = (char *)udir.c_str();
1872  if (clist.length() > 0)
1873  opts.clist = (char *)clist.c_str();
1874  if (cpass.length() > 0)
1875  opts.cpass = (char *)cpass.c_str();
1876  opts.keepcreds = keepcreds;
1877  if (expcreds.length() > 0)
1878  opts.expcreds = (char *)expcreds.c_str();
1879 
1880  // Notify init options, if required
1881  opts.Print(pwdTrace);
1882  //
1883  // Setup the plug-in with the chosen options
1884  return XrdSecProtocolpwd::Init(opts,erp);
1885  }
1886 
1887  // Notify init options, if required
1888  opts.Print(pwdTrace);
1889  //
1890  // Setup the plug-in with the defaults
1891  return XrdSecProtocolpwd::Init(opts,erp);
1892 }}
1893 
1894 
1895 /******************************************************************************/
1896 /* X r d S e c P r o t o c o l p w d O b j e c t */
1897 /******************************************************************************/
1898 
1900 
1901 extern "C"
1902 {
1904  const char *hostname,
1905  XrdNetAddrInfo &endPoint,
1906  const char *parms,
1907  XrdOucErrInfo *erp)
1908 {
1909  XrdSecProtocolpwd *prot;
1910  int options = XrdSecNOIPCHK;
1911 
1912  //
1913  // Get a new protocol object
1914  if (!(prot = new XrdSecProtocolpwd(options, hostname, endPoint, parms))) {
1915  const char *msg = "Secpwd: Insufficient memory for protocol.";
1916  if (erp)
1917  erp->setErrInfo(ENOMEM, msg);
1918  else
1919  std::cerr <<msg <<std::endl;
1920  return (XrdSecProtocol *)0;
1921  }
1922  //
1923  // We are done
1924  if (!erp)
1925  std::cerr << "protocol object instantiated" << std::endl;
1926  return prot;
1927 }}
1928 
1929 
1930 /******************************************************************************/
1931 /* P r i v a t e M e t h o d s */
1932 /******************************************************************************/
1933 
1934 //__________________________________________________________________________
1935 int XrdSecProtocolpwd::ParseCrypto(XrdSutBuffer *buf)
1936 {
1937  // Parse received buffer for the crypto module to be used.
1938  // Parse crypto list clist, extracting the first available module
1939  // and getting a related local cipher and a related reference
1940  // cipher to be used to agree the session cipher; the local lists
1941  // crypto info is updated, if needed
1942  // The results are used to fill the handshake part of the protocol
1943  // instance.
1944  EPNAME("ParseCrypto");
1945 
1946  // Check inputs
1947  if (!buf) {
1948  PRINT("invalid input ("<<buf<<")");
1949  return -1;
1950  }
1951 
1952  String clist = "";
1953  XrdSutBucket *bck = 0;
1954  // Check type of buffer we got
1955  if (!buf->GetNBuckets()) {
1956  // If the bucket list is empty we assume this being the first iteration
1957  // step (the step is not defined at this point).
1958  // The option field should contain the relevant information
1959  String opts = buf->GetOptions();
1960  if (!(opts.length())) {
1961  DEBUG("missing options - bad format");
1962  return -1;
1963  }
1964  //
1965  // Extract crypto module list, if any
1966  int ii = opts.find("c:");
1967  if (ii >= 0) {
1968  clist.assign(opts, ii+2);
1969  clist.erase(clist.find(','));
1970  } else {
1971  PRINT("crypto information not found in options");
1972  return -1;
1973  }
1974  } else {
1975  //
1976  // Extract crypto module name from the buffer
1977  if (!(bck = buf->GetBucket(kXRS_cryptomod))) {
1978  PRINT("cryptomod buffer missing");
1979  return -1;
1980  }
1981  bck->ToString(clist);
1982  }
1983  DEBUG("parsing list: "<<clist.c_str());
1984 
1985  // Load module and define relevant pointers
1986  hs->CryptoMod = "";
1987  // Parse list
1988  if (clist.length()) {
1989  int from = 0;
1990  while ((from = clist.tokenize(hs->CryptoMod, from, '|')) != -1) {
1991  // Check this module
1992  if (hs->CryptoMod.length()) {
1993  // Load the crypto factory
1995  int fid = hs->CF->ID();
1996  int i = 0;
1997  // Retrieve the index in local table
1998  while (i < ncrypt) {
1999  if (cryptID[i] == fid) break;
2000  i++;
2001  }
2002  if (i >= ncrypt) {
2003  if (ncrypt == XrdCryptoMax) {
2004  PRINT("max number of crypto slots reached - do nothing");
2005  return 0;
2006  } else {
2007  // Add new entry
2008  cryptID[i] = fid;
2009  ncrypt++;
2010  }
2011  }
2012  // On servers the ref cipher should be defined at this point
2013  hs->Rcip = refcip[i];
2014  // we are done
2015  return 0;
2016  }
2017  }
2018  }
2019  }
2020 
2021  return 1;
2022 }
2023 
2024 //____________________________________________________________________
2025 bool XrdSecProtocolpwd::CheckCreds(XrdSutBucket *creds, int ctype)
2026 {
2027  // Check credentials against information in password file
2028  EPNAME("CheckCreds");
2029  bool match = 0;
2030 
2031  // Check inputs
2032  if (!hs->CF || !creds || !hs->Pent) {
2033  PRINT("Invalid inputs ("<<hs->CF<<","<<creds<<","<<hs->Pent<<")");
2034  return match;
2035  }
2036  // Make sure there is something to check against
2037  if (ctype != kpCT_afs && ctype != kpCT_afsenc &&
2038  (!(hs->Pent->buf1.buf) || hs->Pent->buf1.len <= 0)) {
2039  NOTIFY("Cached information about creds missing");
2040  return match;
2041  }
2042  //
2043  // Create a buffer to store credentials, if required
2044  int len = creds->size+4;
2045  char *cbuf = (KeepCreds) ? new char[len] : (char *)0;
2046 
2047  //
2048  // Separate treatment for crypt-like creds
2049  if (ctype != kpCT_crypt && ctype != kpCT_afs && ctype != kpCT_afsenc) {
2050  //
2051  // Create a bucket for the salt to easy encryption
2052  XrdSutBucket *tmps = new XrdSutBucket();
2053  if (!tmps) {
2054  PRINT("Could not allocate working buckets area for the salt");
2055  return match;
2056  }
2057  tmps->SetBuf(hs->Pent->buf1.buf, hs->Pent->buf1.len);
2058  //
2059  // Save input bucket if creds have to be kept
2060  if (KeepCreds) {
2061  memcpy(cbuf, "pwd:", 4);
2062  memcpy(cbuf+4, creds->buffer, creds->size);
2063  }
2064  //
2065  // Hash received buffer for the comparison
2066  DoubleHash(hs->CF,creds,tmps);
2067  // Compare
2068  if (hs->Pent->buf2.len == creds->size)
2069  if (!memcmp(creds->buffer, hs->Pent->buf2.buf, creds->size))
2070  match = 1;
2071  SafeDelete(tmps);
2072  //
2073  // recover input creds
2074  if (match && KeepCreds)
2075  creds->SetBuf(cbuf, len);
2076 
2077  } else {
2078 #ifdef HAVE_CRYPT
2079  // Crypt-like: get the pwhash
2080  String passwd(creds->buffer,creds->size+1);
2081  passwd.reset(0,creds->size,creds->size);
2082  // Get the crypt
2083  char *pass_crypt = crypt(passwd.c_str(), hs->Pent->buf1.buf);
2084  // Compare
2085  if (!strncmp(pass_crypt, hs->Pent->buf1.buf, hs->Pent->buf1.len + 1))
2086  match = 1;
2087  if (match && KeepCreds) {
2088  memcpy(cbuf, "cpt:", 4);
2089  memcpy(cbuf+4, creds->buffer, creds->size);
2090  creds->SetBuf(cbuf, len);
2091  }
2092 #else
2093  NOTIFY("Crypt-like passwords (via crypt(...)) not supported");
2094  match = 0;
2095 #endif
2096  }
2097 
2098  // Cleanup
2099  if (cbuf)
2100  delete[] cbuf;
2101 
2102  // We are done
2103  return match;
2104 }
2105 
2106 //________________________________________________________________________
2107 bool XrdSecProtocolpwd::CheckCredsAFS(XrdSutBucket *, int)
2108 {
2109  // Check AFS credentials - not supported
2110  return 0;
2111 }
2112 
2113 //____________________________________________________________________
2114 int XrdSecProtocolpwd::SaveCreds(XrdSutBucket *creds)
2115 {
2116  // Save credentials in creds in the password file
2117  // Returns 0 if ok, -1 otherwise
2118  EPNAME("SaveCreds");
2119  XrdSutPFCacheRef pfeRef;
2120 
2121  // Check inputs
2122  if ((hs->User.length() <= 0) || !hs->CF || !creds) {
2123  PRINT("Bad inputs ("<<hs->User.length()<<","<<hs->CF<<","
2124  <<creds<<")");
2125  return -1;
2126  }
2127  // Build effective tag
2128  String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
2129  //
2130  // Update entry in cache, if there, or add one
2131  XrdSutPFEntry *cent = cacheAdmin.Add(pfeRef, wTag.c_str());
2132  if (!cent) {
2133  PRINT("Could not get entry in cache");
2134  return -1;
2135  }
2136  // Generate a salt and fill it in
2137  char *tmps = XrdSutRndm::GetBuffer(8,3);
2138  if (!tmps) {
2139  PRINT("Could not generate salt: out-of-memory");
2140  return -1;
2141  }
2142  XrdSutBucket *salt = new XrdSutBucket(tmps,8);
2143  if (!salt) {
2144  PRINT("Could not create salt bucket");
2145  return -1;
2146  }
2147  cent->buf1.SetBuf(salt->buffer,salt->size);
2148  //
2149  // Now we sign the creds with the salt
2150  DoubleHash(hs->CF,creds,salt);
2151  // and fill in the creds
2152  cent->buf2.SetBuf(creds->buffer,creds->size);
2153  //
2154  // Set entry status OK
2155  cent->status = kPFE_ok;
2156  //
2157  // Save entry
2158  cent->mtime = hs->TimeStamp;
2159  //
2160  DEBUG("Entry for tag: "<<wTag<<" updated in cache");
2161  //
2162  // Flush cache content to source file
2163  XrdSysPrivGuard priv(getuid(), getgid());
2164  if (priv.Valid()) {
2165  if (cacheAdmin.Flush() != 0) {
2166  PRINT("WARNING: some problem flushing to admin file after updating "<<wTag);
2167  }
2168  }
2169  //
2170  // We are done
2171  return 0;
2172 }
2173 
2174 //____________________________________________________________________
2175 int XrdSecProtocolpwd::ExportCreds(XrdSutBucket *creds)
2176 {
2177  // Export client credentials to a PF file to be used as autologin
2178  // in a next step.
2179  // Returns 0 if ok, -1 otherwise
2180  EPNAME("ExportCreds");
2181 
2182  // Check inputs
2183  if ((hs->User.length() <= 0) || !hs->CF || !creds) {
2184  PRINT("Bad inputs ("<<hs->User.length()<<","<<hs->CF<<","
2185  <<creds<<")");
2186  return -1;
2187  }
2188 
2189  // Check inputs
2190  if (FileExpCreds.length() <= 0) {
2191  PRINT("File (template) undefined - do nothing");
2192  return -1;
2193  }
2194 
2195  // Expand templated keywords, if needed
2196  String filecreds = FileExpCreds;
2197  // Resolve place-holders, if any
2198  if (XrdSutResolve(filecreds, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
2199  PRINT("Problems resolving templates in "<<filecreds);
2200  return -1;
2201  }
2202  DEBUG("Exporting client creds to: "<<filecreds);
2203 
2204  // Make sure the directory exists
2205  int lsl = filecreds.rfind('/');
2206  PRINT("Exporting client creds to: "<<filecreds<<" "<<lsl);
2207  if (lsl != STR_NPOS) {
2208  String dir(filecreds, 0, lsl-1);
2209  PRINT("asserting dir: "<<dir);
2210  if (XrdSutMkdir(dir.c_str(), 0700) != 0) {
2211  PRINT("Problems creating directory "<<dir);
2212  return -1;
2213  }
2214  }
2215 
2216  if (FmtExpCreds == 0) {
2217  // Attach or create the file
2218  XrdSutPFile pfcreds(filecreds.c_str());
2219  if (!pfcreds.IsValid()) {
2220  PRINT("Problem attaching / creating file "<<filecreds);
2221  return -1;
2222  }
2223  //
2224  // Build effective tag
2225  String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
2226  //
2227  // Create and fill a new entry
2228  XrdSutPFEntry ent;
2229  ent.SetName(wTag.c_str());
2230  ent.status = kPFE_ok;
2231  ent.cnt = 0;
2232  if (!strncmp(creds->buffer, "pwd:", 4)) {
2233  // Skip initial "pwd:"
2234  ent.buf1.SetBuf(creds->buffer+4, creds->size-4);
2235  } else {
2236  // For crypt and AFS we keep that to be able to distinguish
2237  // later on
2238  ent.buf1.SetBuf(creds->buffer,creds->size);
2239  }
2240  //
2241  // Write entry
2242  ent.mtime = time(0);
2243  pfcreds.WriteEntry(ent);
2244  DEBUG("New entry for "<<wTag<<" successfully written to file: "
2245  <<filecreds);
2246  } else {
2247  char *buf = 0, *out = 0;
2248  int sz = -1;
2249  // Create buffer to keep the credentials, if not already done
2250  sz = creds->size + 5;
2251  if ((buf = (char *) malloc(sz))) {
2252  memcpy(buf, "&pwd", 4);
2253  buf[4] = 0;
2254  memcpy(buf+5, creds->buffer, creds->size);
2255  // Put in hex
2256  if (FmtExpCreds == 1) {
2257  out = new char[2*sz+1];
2258  XrdSutToHex(buf, sz, out);
2259  }
2260  } else {
2261  PRINT("Problem creating buffer for exported credentials!");
2262  return -1;
2263  }
2264 
2265  // Open the file, truncating if already existing
2266  int fd = open(filecreds.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
2267  if (fd < 0) {
2268  PRINT("problems creating file - errno: " << errno);
2269  if (buf) {free(buf); buf = 0;}
2270  SafeDelete(out);
2271  return -1;
2272  }
2273 
2274  const char *pw = 0;
2275  int lw = -1;
2276  if (FmtExpCreds == 1) {
2277  // Hex form
2278  pw = (const char *)out;
2279  lw = 2*sz + 1;
2280  } else if (FmtExpCreds == 3) {
2281  // Ignore keywords
2282  int offs = (hs->SysPwd == 2) ? 9 : 5;
2283  pw = (const char *)(buf + offs);
2284  lw = sz - offs;
2285  } else {
2286  pw = (const char *)buf;
2287  lw = sz;
2288  }
2289  // Write out now
2290  int nw = 0, written = 0;
2291  while (lw) {
2292  if ((nw = write(fd, pw + written, lw)) < 0) {
2293  if (errno == EINTR) {
2294  errno = 0;
2295  continue;
2296  } else {
2297  break;
2298  }
2299  }
2300  // Count
2301  written += nw;
2302  lw -= nw;
2303  }
2304 
2305  // Cleanup temporary buffers
2306  if (buf) {free(buf); buf = 0;}
2307  SafeDelete(out);
2308  close(fd);
2309  }
2310  // We are done
2311  return 0;
2312 }
2313 
2314 //____________________________________________________________________
2315 XrdSutBucket *XrdSecProtocolpwd::QueryCreds(XrdSutBuffer *bm,
2316  bool netrc, int &status)
2317 {
2318  // Get credential information to be sent to the server
2319  EPNAME("QueryCreds");
2320  XrdSutPFCacheRef pfeRef;
2321 
2322  // Check inputs
2323  if (!bm || !hs->CF || hs->Tag.length() <= 0) {
2324  PRINT("bad inputs ("<<bm<<","<<hs->CF<<","<<hs->Tag.length()<<")");
2325  return (XrdSutBucket *)0;
2326  }
2327 
2328  //
2329  // Type of creds (for the prompt)
2330  int ctype = (status > kpCT_undef) ? status : kpCT_normal;
2331  netrc = ((ctype == kpCT_normal || ctype == kpCT_onetime ||
2332  ctype == kpCT_old || ctype == kpCT_crypt)) ? netrc : 0;
2333  //
2334  // reset status
2335  status = kpCI_undef;
2336  // Output bucket
2337  XrdSutBucket *creds = new XrdSutBucket();
2338  if (!creds) {
2339  PRINT("Could allocate bucket for creds");
2340  return (XrdSutBucket *)0;
2341  }
2342  creds->type = kXRS_creds;
2343 
2344  //
2345  // Build effective tag
2346  String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
2347 
2348  //
2349  // If creds are available in the environment pick them up and use them
2350  char *cf = 0;
2351  char *cbuf = getenv("XrdSecCREDS");
2352  if (cbuf) {
2353  int len = strlen(cbuf);
2354  // From hex
2355  int sz = len;
2356  char *out = new char[sz/2+2];
2357  XrdSutFromHex((const char *)cbuf, out, len);
2358  if ((cf = strstr(out, "&pwd"))) {
2359  cf += 5;
2360  len -= 5;
2361  if (len > 0) {
2362  // Get prefix
2363  char pfx[5] = {0};
2364  memcpy(pfx, cf, 4);
2365  cf += 4;
2366  len -= 4;
2367  if (len > 0) {
2368  DEBUG("using "<<len<<" bytes of creds from the environment; pfx: "<<pfx);
2369  // Create or Fill entry in cache
2370  hs->Pent = cacheAlog.Add(pfeRef, wTag.c_str());
2371  if (hs->Pent) {
2372  // Try only once
2373  if (hs->Pent->cnt == 0) {
2374  // Set buf
2375  creds->SetBuf(cf,len);
2376  // Fill entry
2377  if (strncmp(pfx,"pwd",3))
2378  hs->Pent->status = kPFE_crypt;
2379  hs->Pent->mtime = hs->TimeStamp;
2380  hs->Pent->buf1.SetBuf(cf, len);
2381  // Just in case we need the passwd itself (like in crypt)
2382  hs->Pent->buf2.SetBuf(cf, len);
2383  // Tell the server
2384  if (!strncmp(pfx,"afs",3)) {
2385  String afsInfo = "c";
2386  if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
2387  PRINT("Warning: problems updating bucket with AFS info");
2388  }
2389  // Update status
2390  status = kpCI_exact;
2391  // We are done
2392  return creds;
2393  } else {
2394  // Cleanup
2395  hs->Pent->buf1.SetBuf();
2396  hs->Pent->buf2.SetBuf();
2397  }
2398  } else {
2399  PRINT("Could create new entry in cache");
2400  return (XrdSutBucket *)0;
2401  }
2402  }
2403  }
2404  }
2405  }
2406  pfeRef.UnLock(); // Unlock pointer if we got a lock on it!
2407 
2408  //
2409  // Extract AFS info (the cell), if any
2410  String afsInfo;
2411  if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
2412  XrdSutBucket *bafs = bm->GetBucket(kXRS_afsinfo);
2413  if (bafs)
2414  bafs->ToString(afsInfo);
2415  }
2416  //
2417  // Search information in autolog file(s) first, if required
2418  if (netrc) {
2419  //
2420  // Make sure cache it is up-to-date
2421  if (PFAlog.IsValid()) {
2422  if (cacheAlog.Refresh() != 0) {
2423  PRINT("problems assuring cache update for file alog ");
2424  }
2425  }
2426  //
2427  // We may already have an entry in the cache
2428  bool wild = 0;
2429  hs->Pent = cacheAlog.Get(pfeRef, wTag.c_str(),&wild);
2430  // Retrieve pwd information if ok
2431  if (hs->Pent && hs->Pent->buf1.buf) {
2432  if (hs->Pent->cnt == 0) {
2433  cf = hs->Pent->buf1.buf;
2434  bool afspwd = strncmp(cf,"afs",3) ? 0 : 1;
2435  if (!strncmp(cf,"cpt",3) || afspwd) {
2436  int len = hs->Pent->buf1.len;
2437  cf += 4;
2438  len -= 4;
2439  hs->Pent->status = kPFE_crypt;
2440  hs->Pent->mtime = hs->TimeStamp;
2441  hs->Pent->buf1.SetBuf(cf, len);
2442  // Just in case we need the passwd itself (like in crypt)
2443  hs->Pent->buf2.SetBuf(cf, len);
2444  // Tell the server
2445  if (afspwd) {
2446  afsInfo = "c";
2447  if (bm->UpdateBucket(afsInfo, kXRS_afsinfo) != 0)
2448  PRINT("Warning: problems updating bucket with AFS info");
2449  }
2450  }
2451  // Fill output with double hash
2452  creds->SetBuf(hs->Pent->buf1.buf,hs->Pent->buf1.len);
2453  // Update status
2454  status = wild ? kpCI_wildcard : kpCI_exact;
2455  // We are done
2456  return creds;
2457  } else {
2458  // Entry not ok: probably previous attempt failed: discard
2459  hs->Pent->buf1.SetBuf();
2460  }
2461  }
2462  pfeRef.UnLock(); // In case we have the lock release it.
2463 
2464  // for crypt-like, look also into a .netrc-like file, if any
2465  String passwd;
2466  String host(hs->Tag,hs->Tag.find("@",0)+1,hs->Tag.find(":",0)-1);
2467  if (QueryNetRc(host, passwd, status) == 0) {
2468  // Create or Fill entry in cache
2469  if ((hs->Pent = cacheAlog.Add(pfeRef, wTag.c_str()))) {
2470  // Fill entry
2471  hs->Pent->status = kPFE_crypt;
2472  hs->Pent->mtime = hs->TimeStamp;
2473  hs->Pent->buf1.SetBuf(passwd.c_str(),passwd.length());
2474  // Fill output
2475  creds->SetBuf(passwd.c_str(),passwd.length());
2476  // Update status
2477  status = kpCI_exact;
2478  // We are done
2479  return creds;
2480  } else {
2481  PRINT("Could create new entry in cache");
2482  return (XrdSutBucket *)0;
2483  }
2484  }
2485  }
2486  //
2487  // Create or Fill entry in cache
2488  if (!(hs->Pent) && !(hs->Pent = cacheAlog.Add(pfeRef, wTag.c_str()))) {
2489  PRINT("Could create new entry in cache");
2490  return (XrdSutBucket *)0;
2491  }
2492 
2493  //
2494  // If a previous attempt was successful re-use same passwd
2495  if (hs->Pent && hs->Pent->buf1.buf && hs->Pent->cnt == 0) {
2496  // Fill output
2497  creds->SetBuf(hs->Pent->buf1.buf,hs->Pent->buf1.len);
2498  // Update status
2499  status = kpCI_exact;
2500  // We are done
2501  return creds;
2502  }
2503 
2504  //
2505  // We are here because:
2506  // 1) autologin disabled or no autologin info found
2507  // ==> hs->Pent empty ==> prompt for password
2508  // 2) we need to send a new password hash because it was wrong
2509  // ==> hs->Pent->buf2 empty ==> prompt for password
2510  // 3) we need to send a new password hash because it has expired
2511  // (either one-time or too old)
2512  // ==> query hs->Pent->buf2 before prompting
2513  // 4) we need to send a real password because the server uses crypt()
2514  // or AFS
2515  // ==> query hs->Pent->buf2 from previous prompt
2516 
2517  //
2518  // If the previously cached entry has a second (final) passwd
2519  // use it. This is the case when the real passwd is required (like in
2520  // crypt), we may have it in cache from a previous prompt
2521  if (ctype == kpCT_crypt || ctype == kpCT_afs) {
2522  if (hs->Pent && hs->Pent->buf2.buf) {
2523  if (ctype == kpCT_afs) {
2524  String passwd(hs->Pent->buf2.buf,hs->Pent->buf2.len);
2525  // Fill output
2526  creds->SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
2527  // Not needed anymore
2528  bm->Deactivate(kXRS_afsinfo);
2529  } else {
2530  // Fill output
2531  creds->SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
2532  }
2533  // Save info in the first buffer and reset the second buffer
2534  hs->Pent->buf1.SetBuf(hs->Pent->buf2.buf,hs->Pent->buf2.len);
2535  hs->Pent->buf2.SetBuf();
2536  // Update status
2537  status = kpCI_exact;
2538  // We are done
2539  return creds;
2540  }
2541  }
2542 
2543  //
2544  // From now we need to prompt the user: we can do this only if
2545  // connected to a terminal
2546  if (!(hs->Tty)) {
2547  NOTIFY("Not connected to tty: cannot prompt user for credentials");
2548  return (XrdSutBucket *)0;
2549  }
2550 
2551  //
2552  // Prompt
2553  char prompt[XrdSutMAXPPT] = {0};
2554  if (ctype == kpCT_onetime)
2555  snprintf(prompt,XrdSutMAXPPT, "Password for %s not active: "
2556  "starting activation handshake.",hs->Tag.c_str());
2557  //
2558  // Prepare the prompt
2559  if (ctype == kpCT_new) {
2560  snprintf(prompt,XrdSutMAXPPT, "Enter new password: ");
2561  } else if (ctype == kpCT_crypt) {
2562  String host(hs->Tag,hs->Tag.find("@",0)+1,hs->Tag.find(":",0)-1);
2563  snprintf(prompt,XrdSutMAXPPT, "Password for %s@%s: ",
2564  hs->User.c_str(), host.c_str());
2565  } else if (ctype == kpCT_afs || ctype == kpCT_afsenc) {
2566  snprintf(prompt,XrdSutMAXPPT, "AFS password for %s@%s: ",
2567  hs->User.c_str(), hs->AFScell.c_str());
2568  } else {
2569  // Normal prompt
2570  snprintf(prompt,XrdSutMAXPPT,"Password for %s:",hs->Tag.c_str());
2571  }
2572  //
2573  // Inquire password
2574  int natt = MaxPrompts;
2575  String passwd = "";
2576  bool changepwd =0;
2577  while (natt-- && passwd.length() <= 0) {
2578  XrdSutGetPass(prompt, passwd);
2579  // If in the format $changepwd$<passwd> we are asking for
2580  // a password change
2581  if (passwd.beginswith("$changepwd$")) {
2582  PRINT("Requesting a password change");
2583  changepwd = 1;
2584  passwd.erase("$changepwd$",0,strlen("$changepwd$"));
2585  }
2586  if (passwd.length()) {
2587  // Fill in password
2588  creds->SetBuf(passwd.c_str(),passwd.length());
2589  if (ctype != kpCT_crypt && ctype != kpCT_afs) {
2590  // Self-Hash
2591  DoubleHash(hs->CF,creds,creds);
2592  // Update status
2593  status = kpCI_prompt;
2594  } else if (ctype == kpCT_afs) {
2595 
2596  }
2597  // Save creds to update auto-login file later
2598  // It will be flushed to file if required
2599  if (changepwd)
2600  hs->Pent->status = kPFE_onetime;
2601  else
2602  hs->Pent->status = kPFE_ok;
2603  hs->Pent->buf1.SetBuf(creds->buffer,creds->size);
2604  //
2605  // Just in case we need the passwd itself (like in crypt)
2606  hs->Pent->buf2.SetBuf(passwd.c_str(),passwd.length());
2607  // Update autologin, if required
2608  if (AutoLogin > 0)
2609  UpdateAlog();
2610  }
2611  }
2612  // Cleanup, if we did not get anything
2613  if (passwd.length() <= 0) {
2614  delete creds;
2615  creds = 0;
2616  }
2617  // We are done
2618  return creds;
2619 }
2620 
2621 //____________________________________________________________________
2622 int XrdSecProtocolpwd::UpdateAlog()
2623 {
2624  // Save pass hash in autologin file
2625  // Returns 0 if ok, -1 otherwise
2626  EPNAME("UpdateAlog");
2627 
2628  // Check inputs
2629  if (hs->Tag.length() <= 0) {
2630  PRINT("Tag undefined - do nothing");
2631  return -1;
2632  }
2633  // Check inputs
2634  if (!(hs->Pent) || !(hs->Pent->buf1.buf)) {
2635  NOTIFY("Nothing to do");
2636  return 0;
2637  }
2638  //
2639  // Build effective tag
2640  String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
2641  //
2642  // Make sure the other buffers are reset
2643  hs->Pent->buf2.SetBuf();
2644  hs->Pent->buf3.SetBuf();
2645  hs->Pent->buf4.SetBuf();
2646  //
2647  // Set entry status OK
2648  hs->Pent->status = kPFE_ok;
2649  //
2650  // Reset count
2651  hs->Pent->cnt = 0;
2652  //
2653  // Save entry
2654  hs->Pent->mtime = hs->TimeStamp;
2655  //
2656  DEBUG("Entry for tag: "<<wTag<<" updated in cache");
2657  //
2658  // Flush cache content to source file
2659  if (cacheAlog.Flush() != 0) {
2660  PRINT("WARNING: some problem flushing to alog file after updating "<<wTag);
2661  }
2662  //
2663  // We are done
2664  return 0;
2665 }
2666 
2667 //____________________________________________________________________
2668 int XrdSecProtocolpwd::QueryUser(int &status, String &cmsg)
2669 {
2670  // Check that info about the defined user is available
2671  EPNAME("QueryUser");
2672  XrdSutPFCacheRef pfeRef;
2673 
2674  DEBUG("Enter: " << hs->User);
2675 
2676  // Check inputs
2677  if (hs->User.length() <= 0 || !hs->CF || !hs->Cref) {
2678  PRINT("Invalid inputs ("<<hs->User.length()<<","<<hs->CF<<","<<hs->Cref<<")");
2679  return -1;
2680  }
2681  //
2682  // Build effective tag
2683  String wTag = hs->Tag + '_'; wTag += hs->CF->ID();
2684  //
2685  // Default status
2686  status = kPFE_disabled;
2687  int bad = -1;
2688  cmsg = "";
2689  //
2690  // Check first info in user's home, if allowed
2691  if (UserPwd) {
2692  // Get userinfo
2693  struct passwd *pw;
2694  XrdSysPwd thePwd(hs->User.c_str(), &pw);
2695  int rcst = 0;
2696  kXR_int32 mtime = -1;
2697  bool fcrypt = 0;
2698  String File;
2699  if (pw) {
2700  File.resize(strlen(pw->pw_dir)+FileUser.length()+10);
2701  File.assign(pw->pw_dir, 0);
2702  File += FileUser;
2703  // Get status
2704  struct stat st;
2705  if ((rcst = stat(File.c_str(),&st)) != 0 && errno == ENOENT) {
2706  if (UserPwd > 1) {
2707  // Try special crypt like file
2708  File.replace(FileUser,FileCrypt);
2709  fcrypt = 1;
2710  rcst = 0;
2711  }
2712  }
2713  mtime = (rcst == 0) ? st.st_mtime : mtime;
2714  }
2715 
2716  if (rcst == 0) {
2717  //
2718  // Check cache first
2719  hs->Pent = cacheUser.Get(pfeRef, wTag.c_str());
2720  if (!hs->Pent || (hs->Pent->mtime < mtime)) {
2721  if (!(hs->Pent)) hs->Pent = cacheUser.Add(pfeRef, wTag.c_str());
2722  if (hs->Pent) {
2723  //
2724  // Try the files
2725  if (!fcrypt) {
2726  // Try to attach to File
2727  XrdSutPFile ff(File.c_str(), kPFEopen,0,0);
2728  if (ff.IsValid()) {
2729  // Retrieve pwd information
2730  if (ff.ReadEntry(wTag.c_str(),*(hs->Pent)) > 0) {
2731  bad = 0;
2732  status = hs->Pent->status;
2733  ff.Close();
2734  return 0;
2735  }
2736  ff.Close();
2737  }
2738  } else if (UserPwd > 1) {
2739  String pwhash;
2740  if (QueryCrypt(FileCrypt, pwhash) > 0) {
2741  bad = 0;
2742  status = kPFE_crypt;
2743  // Fill entry
2744  hs->Pent->mtime = hs->TimeStamp;
2745  hs->Pent->status = status;
2746  hs->Pent->cnt = 0;
2747  if (!FileCrypt.beginswith("afs:"))
2748  hs->Pent->buf1.SetBuf(pwhash.c_str(),pwhash.length()+1);
2749  // Trasmit the type of credentials we have found
2750  cmsg = FileCrypt;
2751  return 0;
2752  }
2753  }
2754  }
2755  } else {
2756  // Fill entry
2757  bad = 0;
2758  status = hs->Pent->status;
2759  hs->Pent->mtime = hs->TimeStamp;
2760  if (status == kPFE_crypt)
2761  cmsg = FileCrypt;
2762  return 0;
2763  }
2764  }
2765  }
2766 
2767  //
2768  // Check system info, if enabled
2769  if (SysPwd) {
2770  String pwhash, fn;
2771  if (QueryCrypt(fn, pwhash) > 0) {
2772  bad = 0;
2773  status = kPFE_crypt;
2774  // Fill entry
2775  hs->Pent = cacheUser.Add(pfeRef, wTag.c_str());
2776  hs->Pent->mtime = hs->TimeStamp;
2777  hs->Pent->status = status;
2778  hs->Pent->cnt = 0;
2779  if (!fn.beginswith("afs:"))
2780  hs->Pent->buf1.SetBuf(pwhash.c_str(),pwhash.length()+1);
2781  // Trasmit the type of credentials we have found
2782  cmsg = fn;
2783  return 0;
2784  }
2785  }
2786  //
2787  // Check server admin files
2788  if (PFAdmin.IsValid()) {
2789  //
2790  // Make sure it is uptodate
2791  XrdSysPrivGuard priv(getuid(), getgid());
2792  if (priv.Valid()) {
2793  if (cacheAdmin.Refresh() != 0) {
2794  PRINT("problems assuring cache update for file admin ");
2795  return -1;
2796  }
2797  }
2798  hs->Pent = cacheAdmin.Get(pfeRef, wTag.c_str());
2799  // Retrieve pwd information
2800  if (hs->Pent) {
2801  bad = 0;
2802  status = hs->Pent->status;
2803  if (status == kPFE_allowed) {
2804  if (AutoReg == kpAR_none) {
2805  // No auto-registration: disable
2806  status = kPFE_disabled;
2807  bad = 1;
2808  }
2809  } else if (status >= kPFE_ok) {
2810  // Check failure counter, if required
2811  if (MaxFailures > 0 && hs->Pent->cnt >= MaxFailures) {
2812  status = kPFE_disabled;
2813  bad = 2;
2814  }
2815  // Check expiration time, if required
2816  if (LifeCreds > 0) {
2817  int expt = hs->Pent->mtime + LifeCreds;
2818  int now = hs->TimeStamp;
2819  if (expt < now)
2820  status = kPFE_expired;
2821  }
2822  if (status != kPFE_disabled)
2823  return 0;
2824  }
2825  }
2826  pfeRef.UnLock(); // Unlock hs->Pent if we ever got a lock on it!
2827  }
2828 
2829  //
2830  // If nothing found, auto-registration is enabled, and the tag
2831  // corresponds to a local user, propose auto-registration
2832  if (bad == -1) {
2833  if (AutoReg != kpAR_none) {
2834  status = kPFE_allowed;
2835  if (AutoReg == kpAR_users) {
2836  struct passwd *pw;
2837  XrdSysPwd thePwd(hs->User.c_str(), &pw);
2838  if (!pw) {
2839  status = kPFE_disabled;
2840  bad = 1;
2841  }
2842  }
2843  } else
2844  bad = 1;
2845  }
2846  //
2847  // If disabled, fill salt string with message for the client
2848  if (status == kPFE_disabled) {
2849  char msg[XrdSutMAXPPT];
2850  switch (bad) {
2851  case 1:
2852  snprintf(msg,XrdSutMAXPPT,"user '%s' unknown: auto-registration"
2853  " not allowed: contact %s to register",
2854  hs->User.c_str(),SrvEmail.c_str());
2855  break;
2856  case 2:
2857  snprintf(msg,XrdSutMAXPPT,"max number of failures (%d) reached"
2858  " for user '%s': contact %s to re-activate",
2859  MaxFailures,hs->User.c_str(),SrvEmail.c_str());
2860  break;
2861  default:
2862  msg[0] = '\0';
2863  }
2864  cmsg.insert(msg,0,strlen(msg));
2865  }
2866  //
2867  // We are done
2868  return 0;
2869 }
2870 
2871 //_________________________________________________________________________
2872 int XrdSecProtocolpwd::GetUserHost(String &user, String &host)
2873 {
2874  // Resolve user and host
2875  EPNAME("GetUserHost");
2876 
2877  // Host
2878  host = Entity.host;
2879  if (host.length() <= 0) host = getenv("XrdSecHOST");
2880 
2881  // User
2882  user = Entity.name;
2883  if (user.length() <= 0) user = getenv("XrdSecUSER");
2884 
2885  // If user not given, prompt for it
2886  if (user.length() <= 0) {
2887  //
2888  // Make sure somebody can be prompted
2889  if (!(hs->Tty)) {
2890  NOTIFY("user not defined:"
2891  "not tty: cannot prompt for user");
2892  return -1;
2893  }
2894  //
2895  // This is what we want
2896  String prompt = "Enter user or tag";
2897  if (host.length()) {
2898  prompt.append(" for host ");
2899  prompt.append(host);
2900  }
2901  prompt.append(":");
2902  XrdSutGetLine(user,prompt.c_str());
2903  }
2904 
2905  DEBUG(" user: "<<user<<", host: "<<host);
2906 
2907  // We are done
2908  return 0;
2909 }
2910 
2911 //_________________________________________________________________________
2912 int XrdSecProtocolpwd::AddSerialized(char opt, kXR_int32 step, String ID,
2913  XrdSutBuffer *bls, XrdSutBuffer *buf,
2914  kXR_int32 type,
2915  XrdCryptoCipher *cip)
2916 {
2917  // Serialize buf, and add it encrypted to bls as bucket type
2918  // Cipher cip is used if defined; else PuK rsa .
2919  // If both are undefined the buffer is just serialized and added.
2920  EPNAME("AddSerialized");
2921 
2922  if (!bls || !buf || (opt != 0 && opt != 'c' && opt != 's')) {
2923  PRINT("invalid inputs ("
2924  <<bls<<","<<buf<<","<<opt<<")"
2925  <<" - type: "<<XrdSutBuckStr(type));
2926  return -1;
2927  }
2928 
2929  //
2930  // Add step to indicate the counterpart what we send
2931  if (step > 0) {
2932  bls->SetStep(step);
2933  buf->SetStep(step);
2934  hs->LastStep = step;
2935  }
2936 
2937  //
2938  // If a random tag has been sent and we have a session cipher,
2939  // we sign it
2940  XrdSutBucket *brt = buf->GetBucket(kXRS_rtag);
2941  if (brt && cip) {
2942  //
2943  // Encrypt random tag with session cipher
2944  if (cip->Encrypt(*brt) == 0) {
2945  PRINT("error encrypting random tag");
2946  return -1;
2947  }
2948  //
2949  // Update type
2950  brt->type = kXRS_signed_rtag;
2951  }
2952  // Clients send in any case something session dependent: the server
2953  // may optionally decide that's enough and save one exchange.
2954  if (opt == 'c') {
2955  //
2956  // Add bucket with our timestamp to the main list
2957  if (buf->MarshalBucket(kXRS_timestamp,(kXR_int32)(hs->TimeStamp)) != 0) {
2958  PRINT("error adding bucket with time stamp");
2959  return -1;
2960  }
2961  }
2962  //
2963  // Add an random challenge: if a next exchange is required this will
2964  // allow to prove authenticity of counter part
2965  if (opt == 's' || step != kXPC_autoreg) {
2966  //
2967  // Generate new random tag and create/update bucket
2968  String RndmTag;
2969  XrdSutRndm::GetRndmTag(RndmTag);
2970  //
2971  // Get bucket
2972  if (!(brt = new XrdSutBucket(RndmTag,kXRS_rtag))) {
2973  PRINT("error creating random tag bucket");
2974  return -1;
2975  }
2976  buf->AddBucket(brt);
2977  //
2978  // Get cache entry
2979  if (!hs->Cref) {
2980  PRINT("cache entry not found: protocol error");
2981  return -1;
2982  }
2983  //
2984  // Add random tag to the cache and update timestamp
2985  hs->Cref->buf1.SetBuf(brt->buffer,brt->size);
2986  hs->Cref->mtime = (kXR_int32)hs->TimeStamp;
2987  }
2988  //
2989  // Now serialize the buffer ...
2990  char *bser = 0;
2991  int nser = buf->Serialized(&bser);
2992  //
2993  // Update bucket with this content
2994  XrdSutBucket *bck = 0;;
2995  if (!(bck = bls->GetBucket(type))) {
2996  // or create new bucket, if not existing
2997  if (!(bck = new XrdSutBucket(bser,nser,type))) {
2998  PRINT("error creating bucket "
2999  <<" - type: "<<XrdSutBuckStr(type));
3000  return -1;
3001  }
3002  //
3003  // Add the bucket to the list
3004  bls->AddBucket(bck);
3005  } else {
3006  bck->Update(bser,nser);
3007  }
3008  //
3009  // Encrypted the bucket
3010  if (cip) {
3011  if (cip->Encrypt(*bck) == 0) {
3012  PRINT("error encrypting bucket - cipher "
3013  <<" - type: "<<XrdSutBuckStr(type));
3014  return -1;
3015  }
3016  }
3017  // We are done
3018  return 0;
3019 }
3020 
3021 //_________________________________________________________________________
3022 int XrdSecProtocolpwd::ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm,
3023  String &emsg)
3024 {
3025  // Parse received buffer b, extracting and decrypting the main
3026  // buffer *bm and extracting the session
3027  // cipher and server public keys, if there
3028  // Result used to fill the handshake local variables
3029  EPNAME("ParseClientInput");
3030  XrdSutPFCacheRef pfeRef;
3031 
3032  // Space for pointer to main buffer must be already allocated
3033  if (!br || !bm) {
3034  PRINT("invalid inputs ("<<br<<","<<bm<<")");
3035  emsg = "invalid inputs";
3036  return -1;
3037  }
3038  //
3039  // Get the step
3040  XrdSutBucket *bckm = 0;
3041 
3042  // If first call, not much to do
3043  if (!br->GetNBuckets()) {
3044  // Create the main buffer as a copy of the buffer received
3045  if (!((*bm) = new XrdSutBuffer(br->GetProtocol(),br->GetOptions()))) {
3046  emsg = "error instantiating main buffer";
3047  return -1;
3048  }
3049  //
3050  // Extract server version from options
3051  String opts = br->GetOptions();
3052  int ii = opts.find("v:");
3053  if (ii >= 0) {
3054  String sver(opts,ii+2);
3055  sver.erase(sver.find(','));
3056  hs->RemVers = atoi(sver.c_str());
3057  } else {
3058  hs->RemVers = Version;
3059  emsg = "server version information not found in options:"
3060  " assume same as local";
3061  }
3062  //
3063  // Create cache
3064  if (!(hs->Cref = new XrdSutPFEntry("c"))) {
3065  emsg = "error creating cache";
3066  return -1;
3067  }
3068  //
3069  // Save server version in cache
3070  hs->Cref->status = hs->RemVers;
3071  //
3072  // Extract server ID
3073  String srvid;
3074  ii = opts.find("id:");
3075  if (ii >= 0) {
3076  srvid.assign(opts, ii+3);
3077  srvid.erase(srvid.find(','));
3078  }
3079  //
3080  // Extract priority options
3081  String popt;
3082  ii = opts.find("po:");
3083  if (ii >= 0) {
3084  popt.assign(opts, ii+3);
3085  popt.erase(popt.find(','));
3086  // Parse it
3087  if (popt.beginswith("sys")) {
3088  hs->SysPwd = 1;
3089  } else if (popt.beginswith("afs")) {
3090  hs->SysPwd = 2;
3091  hs->AFScell.assign(popt,3);
3092  }
3093  }
3094  //
3095  // Get user and host
3096  String host;
3097  if (GetUserHost(hs->User,host) != 0) {
3098  emsg = "error getting user and host";
3099  return -1;
3100  }
3101  //
3102  // Build tag and save it into the cache
3103  hs->Tag.resize(hs->User.length()+host.length()+srvid.length()+5);
3104  hs->Tag = hs->User;
3105  if (host.length() > 0)
3106  hs->Tag += ("@" + host);
3107  if (srvid.length() > 0)
3108  hs->Tag += (":" + srvid);
3109  //
3110  // Get server puk from cache and initialize handshake cipher
3111  if (!PFSrvPuk.IsValid()) {
3112  emsg = "file with server public keys invalid";
3113  return -1;
3114  }
3115  char *ptag = new char[host.length()+srvid.length()+10];
3116  if (ptag) {
3117  sprintf(ptag,"%s:%s_%d",host.c_str(),srvid.c_str(),hs->CF->ID());
3118  bool wild = 0;
3119  XrdSutPFEntry *ent = cacheSrvPuk.Get(pfeRef, (const char *)ptag, &wild);
3120  if (ent) {
3121  // Initialize cipher
3122  SafeDelete(hs->Hcip);
3123  if (!(hs->Hcip =
3124  hs->CF->Cipher(0,ent->buf1.buf,ent->buf1.len))) {
3125  PRINT("could not instantiate session cipher "
3126  "using cipher public info from server");
3127  emsg = "could not instantiate session cipher ";
3128  } else {
3129  DEBUG("hsHcip: 0x"<<hs->Hcip->AsHexString());
3130  }
3131  pfeRef.UnLock();
3132  } else {
3133  // Autoreg is the only alternative at this point ...
3134  emsg = "server puk not found in cache - tag: ";
3135  emsg += ptag;
3136  }
3137  SafeDelArray(ptag);
3138  } else
3139  emsg = "could not allocate buffer for server puk tag";
3140  //
3141  // And we are done;
3142  return 0;
3143  }
3144  //
3145  // make sure the cache is still there
3146  if (!hs->Cref) {
3147  emsg = "cache entry not found";
3148  return -1;
3149  }
3150  //
3151  // make sure is not too old
3152  int reftime = hs->TimeStamp - TimeSkew;
3153  if (hs->Cref->mtime < reftime) {
3154  emsg = "cache entry expired";
3155  // Remove: should not be checked a second time
3156  SafeDelete(hs->Cref);
3157  return -1;
3158  }
3159  //
3160  // Get from cache version run by server
3161  hs->RemVers = hs->Cref->status;
3162  //
3163  // Extract the main buffer
3164  if (!(bckm = br->GetBucket(kXRS_main))) {
3165  emsg = "main buffer missing";
3166  return -1;
3167  }
3168  //
3169  // Decrypt, if it makes sense
3170  if (hs->LastStep != kXPC_autoreg) {
3171  //
3172  // make sure the cache is still there
3173  if (!hs->Hcip) {
3174  emsg = "session cipher not found";
3175  return -1;
3176  }
3177  //
3178  // Decrypt it
3179  if (!(hs->Hcip->Decrypt(*bckm))) {
3180  emsg = "error decrypting main buffer with session cipher";
3181  return -1;
3182  }
3183  }
3184  //
3185  // Deserialize main buffer
3186  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3187  emsg = "error deserializing main buffer";
3188  return -1;
3189  }
3190  //
3191  // If (new) server public keys are there extract and save them
3192  bool newpuk = 0;
3193  XrdSutBuckList *bcklst = (*bm)->GetBuckList();
3194  XrdSutBucket *bp = bcklst->Begin();
3195  while (bp) {
3196  if (bp->type == kXRS_puk) {
3197  newpuk = 1;
3198  // ID is in the first 4 chars ( ....'\0'<puk>)
3199  char cid[5] = {0};
3200  memcpy(cid, bp->buffer, 5);
3201  int id = atoi(cid);
3202  // Build tag
3203  String ptag(hs->Tag);
3204  ptag.erase(0,ptag.find('@')+1);
3205  ptag += '_';
3206  ptag += cid;
3207  // Update or create new entry
3208  XrdSutPFEntry *ent = cacheSrvPuk.Add(pfeRef, ptag.c_str());
3209  if (ent) {
3210  // Set buffer
3211  ent->buf1.SetBuf((bp->buffer)+5,(bp->size)-5);
3212  ent->mtime = hs->TimeStamp;
3213  if (id == hs->CF->ID()) {
3214  // Initialize cipher
3215  SafeDelete(hs->Hcip);
3216  if (!(hs->Hcip =
3217  hs->CF->Cipher(0,ent->buf1.buf,ent->buf1.len))) {
3218  PRINT("could not instantiate session cipher "
3219  "using cipher public info from server");
3220  emsg = "could not instantiate session cipher ";
3221  } else {
3222  DEBUG("hsHcip: 0x"<<hs->Hcip->AsHexString());
3223  }
3224  }
3225  pfeRef.UnLock();
3226  } else {
3227  // Autoreg is the only alternative at this point ...
3228  PRINT("could not create entry in cache - tag: "<<ptag);
3229  }
3230  }
3231  // Get next
3232  bp = bcklst->Next();
3233  }
3234  (*bm)->Deactivate(kXRS_puk);
3235  // Update the puk file (for the other sessions ...)
3236  if (newpuk)
3237  cacheSrvPuk.Flush();
3238  //
3239  // We are done
3240  return 0;
3241 }
3242 
3243 //_________________________________________________________________________
3244 int XrdSecProtocolpwd::ParseServerInput(XrdSutBuffer *br, XrdSutBuffer **bm,
3245  String &cmsg)
3246 {
3247  // Parse received buffer b, extracting and decrypting the main
3248  // buffer *bm and extracting the session
3249  // cipher, random tag buckets and user name, if any.
3250  // Results used to fill the local handshake variables
3251  EPNAME("ParseServerInput");
3252 
3253  // Space for pointer to main buffer must be already allocated
3254  if (!br || !bm) {
3255  PRINT("invalid inputs ("<<br<<","<<bm<<")");
3256  cmsg = "invalid inputs";
3257  return -1;
3258  }
3259  //
3260  // Get the step
3261  XrdSutBucket *bck = 0;
3262  XrdSutBucket *bckm = 0;
3263  //
3264  // Extract the main buffer
3265  if (!(bckm = br->GetBucket(kXRS_main))) {
3266  cmsg = "main buffer missing";
3267  return -1;
3268  }
3269  //
3270  // First get the session cipher
3271  if ((bck = br->GetBucket(kXRS_puk))) {
3272  //
3273  // Cleanup
3274  SafeDelete(hs->Hcip);
3275  //
3276  // Prepare cipher agreement: make sure we have the reference cipher
3277  if (!hs->Rcip) {
3278  cmsg = "reference cipher missing";
3279  return -1;
3280  }
3281  // Prepare cipher agreement: get a copy of the reference cipher
3282  if (!(hs->Hcip = hs->CF->Cipher(*hs->Rcip))) {
3283  cmsg = "cannot get reference cipher";
3284  return -1;
3285  }
3286  //
3287  // Instantiate the session cipher
3288  if (!(hs->Hcip->Finalize(bck->buffer,bck->size,0))) {
3289  cmsg = "cannot finalize session cipher";
3290  return -1;
3291  }
3292  //
3293  // We need it only once
3294  br->Deactivate(kXRS_puk);
3295  }
3296 
3297  //
3298  // Decrypt the main buffer with the session cipher, if available
3299  if (hs->Hcip) {
3300  if (!(hs->Hcip->Decrypt(*bckm))) {
3301  cmsg = "error decrypting main buffer with session cipher";
3302  return -1;
3303  }
3304  }
3305  //
3306  // Deserialize main buffer
3307  if (!((*bm) = new XrdSutBuffer(bckm->buffer,bckm->size))) {
3308  cmsg = "error deserializing main buffer";
3309  return -1;
3310  }
3311  //
3312  // Get version run by client, if there
3313  if (hs->RemVers == -1) {
3314  if ((*bm)->UnmarshalBucket(kXRS_version,hs->RemVers) != 0) {
3315  hs->RemVers = Version;
3316  cmsg = "client version information not found in options:"
3317  " assume same as local";
3318  } else {
3319  (*bm)->Deactivate(kXRS_version);
3320  }
3321  }
3322 
3323  //
3324  // Get cache entry or create a new one
3325  if (!hs->Cref) {
3326  // Create it
3327  if (!(hs->Cref = new XrdSutPFEntry(hs->ID.c_str()))) {
3328  cmsg = "cannot create cache entry";
3329  return -1;
3330  }
3331  } else {
3332  //
3333  // make sure cache is not too old
3334  int reftime = hs->TimeStamp - TimeSkew;
3335  if (hs->Cref->mtime < reftime) {
3336  cmsg = "cache entry expired";
3337  SafeDelete(hs->Cref);
3338  return -1;
3339  }
3340  }
3341 
3342  //
3343  // Extract user name, if any
3344  if ((bck = (*bm)->GetBucket(kXRS_user))) {
3345  if (hs->User.length() <= 0) {
3346  bck->ToString(hs->User);
3347  // Build tag
3348  hs->Tag = hs->User;
3349  }
3350  (*bm)->Deactivate(kXRS_user);
3351  }
3352  //
3353  // We are done
3354  return 0;
3355 }
3356 
3357 //__________________________________________________________________
3358 void XrdSecProtocolpwd::ErrF(XrdOucErrInfo *einfo, kXR_int32 ecode,
3359  const char *msg1, const char *msg2,
3360  const char *msg3)
3361 {
3362  // Filling the error structure
3363  EPNAME("ErrF");
3364 
3365  char *msgv[12];
3366  int k, i = 0, sz = strlen("Secpwd");
3367 
3368  //
3369  // Code message, if any
3370  int cm = (ecode >= kPWErrParseBuffer &&
3371  ecode <= kPWErrError) ? (ecode-kPWErrParseBuffer) : -1;
3372  const char *cmsg = (cm > -1) ? gPWErrStr[cm] : 0;
3373 
3374  //
3375  // Build error message array
3376  msgv[i++] = (char *)"Secpwd"; //0
3377  if (cmsg) {msgv[i++] = (char *)": "; //1
3378  msgv[i++] = (char *)cmsg; //2
3379  sz += strlen(msgv[i-1]) + 2;
3380  }
3381  if (msg1) {msgv[i++] = (char *)": "; //3
3382  msgv[i++] = (char *)msg1; //4
3383  sz += strlen(msgv[i-1]) + 2;
3384  }
3385  if (msg2) {msgv[i++] = (char *)": "; //5
3386  msgv[i++] = (char *)msg2; //6
3387  sz += strlen(msgv[i-1]) + 2;
3388  }
3389  if (msg3) {msgv[i++] = (char *)": "; //7
3390  msgv[i++] = (char *)msg3; //8
3391  sz += strlen(msgv[i-1]) + 2;
3392  }
3393 
3394  // save it (or print it)
3395  if (einfo) {
3396  einfo->setErrInfo(ecode, (const char **)msgv, i);
3397  }
3398  if (QTRACE(Debug)) {
3399  char *bout = new char[sz+10];
3400  if (bout) {
3401  bout[0] = 0;
3402  for (k = 0; k < i; k++)
3403  strcat(bout, msgv[k]);
3404  PRINT(bout);
3405  } else {
3406  for (k = 0; k < i; k++)
3407  PRINT(msgv[k]);
3408  }
3409  }
3410 }
3411 
3412 //__________________________________________________________________
3413 XrdSecCredentials *XrdSecProtocolpwd::ErrC(XrdOucErrInfo *einfo,
3414  XrdSutBuffer *b1,
3415  XrdSutBuffer *b2,
3416  XrdSutBuffer *b3,
3417  kXR_int32 ecode,
3418  const char *msg1,
3419  const char *msg2,
3420  const char *msg3)
3421 {
3422  // Error logging client method
3423 
3424  // Fill the error structure
3425  ErrF(einfo, ecode, msg1, msg2, msg3);
3426 
3427  // Release buffers
3428  REL3(b1,b2,b3);
3429 
3430  // We are done
3431  return (XrdSecCredentials *)0;
3432 }
3433 
3434 //__________________________________________________________________
3435 int XrdSecProtocolpwd::ErrS(String ID, XrdOucErrInfo *einfo,
3436  XrdSutBuffer *b1, XrdSutBuffer *b2,
3437  XrdSutBuffer *b3, kXR_int32 ecode,
3438  const char *msg1, const char *msg2,
3439  const char *msg3)
3440 {
3441  // Error logging server method
3442 
3443  // Fill the error structure
3444  ErrF(einfo, ecode, msg1, msg2, msg3);
3445 
3446  // Release buffers
3447  REL3(b1,b2,b3);
3448 
3449  // We are done
3450  return kpST_error;
3451 }
3452 
3453 //_______________________________________________________________________
3454 int XrdSecProtocolpwd::DoubleHash(XrdCryptoFactory *cf, XrdSutBucket *bck,
3455  XrdSutBucket *s1, XrdSutBucket *s2,
3456  const char *tag)
3457 {
3458  // Apply single or double hash to bck using salts
3459  // in s1 and (if defined) s2.
3460  // Store result in *buf, with the new length in len.
3461  // Return 0 if ok or -1 otherwise
3462  EPNAME("DoubleHash");
3463 
3464  //
3465  // Check inputs
3466  if (!cf || !bck) {
3467  PRINT("Bad inputs "<<cf<<","<<bck<<")");
3468  return -1;
3469  }
3470  //
3471  // At least one salt must be defined
3472  if ((!s1 || s1->size <= 0) && (!s2 || s2->size <= 0)) {
3473  PRINT("Both salts undefined - do nothing");
3474  return 0;
3475  }
3476  //
3477  // Tag length, if there
3478  int ltag = (tag) ? strlen(tag) + 1 : 0;
3479  //
3480  // Get one-way hash function
3481  XrdCryptoKDFun_t KDFun = cf->KDFun();
3483  if (!KDFun || !KDFunLen) {
3484  PRINT("Could not get hooks to one-way hash functions ("
3485  <<KDFun<<","<<KDFunLen<<")");
3486  return -1;
3487  }
3488  //
3489  // Apply first salt, if defined
3490  char *nhash = 0, *thash = bck->buffer;
3491  int nhlen = bck->size;
3492  if (s1 && s1->size > 0) {
3493  if (!(nhash = new char[(*KDFunLen)() + ltag])) {
3494  PRINT("Could not allocate memory for hash - s1");
3495  return -1;
3496  }
3497  if ((nhlen = (*KDFun)(thash,nhlen,
3498  s1->buffer,s1->size,nhash+ltag,0)) <= 0) {
3499  PRINT("Problems hashing - s1");
3500  delete[] nhash;
3501  return -1;
3502  }
3503  thash = nhash;
3504  }
3505  //
3506  // Apply second salt, if defined
3507  if (s2 && s2->size > 0) {
3508  if (!(nhash = new char[(*KDFunLen)() + ltag])) {
3509  PRINT("Could not allocate memory for hash - s2");
3510  return -1;
3511  }
3512  if (thash && thash != bck->buffer) thash += ltag;
3513  if ((nhlen = (*KDFun)(thash,nhlen,
3514  s2->buffer,s2->size,nhash+ltag,0)) <= 0) {
3515  PRINT("Problems hashing - s2");
3516  delete[] nhash;
3517  if (thash && thash != bck->buffer) delete[] thash;
3518  return -1;
3519  }
3520  if (thash && thash != bck->buffer) delete[] thash;
3521  thash = nhash;
3522  }
3523  //
3524  // Add tag if there
3525  if (tag)
3526  memcpy(thash,tag,ltag);
3527  //
3528  // Save result
3529  bck->SetBuf(thash,nhlen+ltag);
3530  //
3531  // We are done
3532  return 0;
3533 }
3534 
3535 //______________________________________________________________________________
3536 int XrdSecProtocolpwd::QueryCrypt(String &fn, String &pwhash)
3537 {
3538  // Retrieve crypt-like password-hash from $HOME/fn or from system password files,
3539  // if accessible.
3540  // To avoid problems with NFS-root-squashing, if 'root' changes temporarily the
3541  // uid/gid to those of the target user (usr).
3542  // If OK, returns pass length and fill 'pass' with the password, null-terminated.
3543  // ('pass' is allocated externally to contain max lpwmax bytes).
3544  // If the file does not exists, return 0 and an empty pass.
3545  // If any problems with the file occurs, return a negative
3546  // code, -2 indicating wrong file permissions.
3547  // If any problem with changing ugid's occurs, prints a warning trying anyhow
3548  // to read the password hash.
3549  EPNAME("QueryCrypt");
3550 
3551  int rc = -1;
3552  int len = 0, n = 0, fid = -1;
3553  pwhash = "";
3554  DEBUG("analyzing file: "<<fn);
3555 
3556  //
3557  // Get the password structure
3558  struct passwd *pw;
3559  XrdSysPwd thePwd(hs->User.c_str(), &pw);
3560  if (!pw) {
3561  PRINT("Cannot get pwnam structure for user "<<hs->User);
3562  return -1;
3563  }
3564  //
3565  // Check the user specific file first, if requested
3566  if (fn.length() > 0) {
3567 
3568  // target uid
3569  int uid = pw->pw_uid;
3570 
3571  // Acquire the privileges, if needed
3572  XrdSysPrivGuard priv(uid, pw->pw_gid);
3573  bool go = priv.Valid();
3574  if (!go) {
3575  PRINT("problems acquiring temporarily identity: "<<hs->User);
3576  }
3577 
3578  // The file
3579  String fpw(pw->pw_dir, strlen(pw->pw_dir) + fn.length() + 5);
3580  if (go) {
3581  fpw += ("/" + fn);
3582  DEBUG("checking file "<<fpw<<" for user "<<hs->User);
3583  }
3584 
3585  // Check first the permissions: should be 0600
3586  struct stat st;
3587  if (go && stat(fpw.c_str(), &st) == -1) {
3588  if (errno != ENOENT) {
3589  PRINT("cannot stat password file "<<fpw<<" (errno:"<<errno<<")");
3590  rc = -1;
3591  } else {
3592  PRINT("file "<<fpw<<" does not exist");
3593  rc = 0;
3594  }
3595  go = 0;
3596  }
3597  if (go &&
3598  (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
3599  (st.st_mode & (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH)) != 0)) {
3600  PRINT("pass file "<<fpw<<": wrong permissions "<<
3601  (st.st_mode & 0777) << " (should be 0600)");
3602  rc = -2;
3603  go = 0;
3604  }
3605 
3606  // Open the file
3607  if (go && (fid = open(fpw.c_str(), O_RDONLY)) == -1) {
3608  PRINT("cannot open file "<<fpw<<" (errno:"<<errno<<")");
3609  rc = -1;
3610  go = 0;
3611  }
3612 
3613  // Read password-hash
3614  char pass[128];
3615  if (go && (n = read(fid, pass, sizeof(pass)-1)) <= 0) {
3616  close(fid);
3617  PRINT("cannot read file "<<fpw<<" (errno:"<<errno<<")");
3618  rc = -1;
3619  go = 0;
3620  }
3621  if (fid > -1)
3622  close(fid);
3623 
3624  // Get rid of special trailing chars
3625  if (go) {
3626  len = n;
3627  while (len-- && (pass[len] == '\n' || pass[len] == 32))
3628  pass[len] = 0;
3629  // Null-terminate
3630  pass[++len] = 0;
3631  rc = len;
3632  // Prepare for output
3633  pwhash = pass;
3634  }
3635  }
3636  //
3637  // If we go a pw-hash we are done
3638  if (pwhash.length() > 0)
3639  return rc;
3640  //
3641  // If not, we check the system files
3642 #ifdef HAVE_SHADOWPW
3643  { // Acquire the privileges; needs to be 'superuser' to access the
3644  // shadow password file
3645  XrdSysPrivGuard priv((uid_t)0, (gid_t)0);
3646  if (priv.Valid()) {
3647  struct spwd *spw = 0;
3648  // System V Rel 4 style shadow passwords
3649  if ((spw = getspnam(hs->User.c_str())) == 0) {
3650  NOTIFY("shadow passwd not accessible to this application");
3651  } else
3652  pwhash = spw->sp_pwdp;
3653  } else {
3654  NOTIFY("problems acquiring temporarily superuser privileges");
3655  }
3656  }
3657 #else
3658  pwhash = pw->pw_passwd;
3659 #endif
3660  //
3661  // This is send back to the client to locate autologin info
3662  fn = "system";
3663  // Check if successful
3664  if ((rc = pwhash.length()) <= 2) {
3665  NOTIFY("passwd hash not available for user "<<hs->User);
3666  pwhash = "";
3667  fn = "";
3668  rc = -1;
3669  }
3670 
3671  // We are done
3672  return rc;
3673 }
3674 
3675 //______________________________________________________________________________
3676 int XrdSecProtocolpwd::QueryNetRc(String host, String &passwd, int &status)
3677 {
3678  // Check netrc-like file defined by env 'XrdSecNETRC' for password information
3679  // matching ('user','host') and return the password in 'passwd'.
3680  // If found, 'status' is filled with 'kpCI_exact' or 'kpCI_wildcard'
3681  // depending the type of match.
3682  // Same syntax as $HOME/.netrc is required; wild cards for hosts are
3683  // supported: examples
3684  //
3685  // machine oplapro027.cern.ch login qwerty password Rt8dsAvV0
3686  // machine lxplus*.cern.ch login poiuyt password WtHAyD0iG
3687  //
3688  // Returns 0 is something found, -1 otherwise.
3689  // NB: file permissions must be: readable/writable by the owner only
3690  EPNAME("QueryNetRc");
3691  passwd = "";
3692  //
3693  // Make sure a file name is defined
3694  String fnrc = getenv("XrdSecNETRC");
3695  if (fnrc.length() <= 0) {
3696  PRINT("File name undefined");
3697  return -1;
3698  }
3699  // Resolve place-holders, if any
3700  if (XrdSutResolve(fnrc, Entity.host, Entity.vorg, Entity.grps, Entity.name) != 0) {
3701  PRINT("Problems resolving templates in "<<fnrc);
3702  return -1;
3703  }
3704  DEBUG("checking file "<<fnrc<<" for user "<<hs->User);
3705 
3706  // Check first the permissions: should be 0600
3707  struct stat st;
3708  if (stat(fnrc.c_str(), &st) == -1) {
3709  if (errno != ENOENT) {
3710  PRINT("cannot stat password file "<<fnrc<<" (errno:"<<errno<<")");
3711  } else {
3712  PRINT("file "<<fnrc<<" does not exist");
3713  }
3714  return -1;
3715  }
3716  if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
3717  (st.st_mode & (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH)) != 0) {
3718  PRINT("pass file "<<fnrc<<": wrong permissions "<<
3719  (st.st_mode & 0777) << " (should be 0600)");
3720  return -2;
3721  }
3722  // Open the file
3723  FILE *fid = fopen(fnrc.c_str(), "r");
3724  if (!fid) {
3725  PRINT("cannot open file "<<fnrc<<" (errno:"<<errno<<")");
3726  return -1;
3727  }
3728  char line[512];
3729  int nm = 0, nmmx = -1;
3730  while (fgets(line, sizeof(line), fid) != 0) {
3731  if (line[0] == '#')
3732  continue;
3733  char word[6][128];
3734  int nword = sscanf(line, "%s %s %s %s %s %s", word[0], word[1],
3735  word[2], word[3], word[4], word[5]);
3736  if (nword != 6) continue;
3737  if (strcmp(word[0], "machine") || strcmp(word[2], "login") ||
3738  strcmp(word[4], "password"))
3739  continue;
3740  // Good entry format
3741  if ((nm = host.matches(word[1])) > 0) {
3742  // Host matches
3743  if (!strcmp(hs->User.c_str(),word[3])) {
3744  // User matches: if exact match we are done
3745  if (nm == host.length()) {
3746  passwd = word[5];
3747  status = kpCI_exact;
3748  break;
3749  }
3750  // Else, we focalise on the best match
3751  if (nm > nmmx) {
3752  nmmx = nm;
3753  passwd = word[5];
3754  status = kpCI_wildcard;
3755  }
3756  }
3757  }
3758  }
3759  //
3760  // Close the file
3761  fclose(fid);
3762  //
3763  // We are done
3764  if (passwd.length() > 0)
3765  return 0;
3766  return -1;
3767 }
3768 
3769 //______________________________________________________________________________
3770 bool XrdSecProtocolpwd::CheckTimeStamp(XrdSutBuffer *bm, int skew, String &emsg)
3771 {
3772  // Check consistency of the time stamp in bucket kXRS_timestamp in bm;
3773  // skew is the allowed difference in times.
3774  // Return 1 if ok, 0 if not
3775  EPNAME("CheckTimeStamp");
3776 
3777  // Check inputs
3778  if (!bm || skew <= 0) {
3779  if (!bm)
3780  emsg = "input buffer undefined ";
3781  else
3782  emsg = "negative skew: invalid ";
3783  return 0;
3784  }
3785 
3786  // We check only if requested and a stronger check has not been done
3787  // successfully already
3788  if (hs->RtagOK || VeriClnt != 1) {
3789  NOTIFY("Nothing to do");
3790  // Deactivate the buffer, if there
3791  if (bm->GetBucket(kXRS_timestamp))
3793  return 1;
3794  }
3795 
3796  //
3797  // Add bucket with our version to the main list
3798  kXR_int32 tstamp = 0;
3799  if (bm->UnmarshalBucket(kXRS_timestamp,tstamp) != 0) {
3800  emsg = "bucket with time stamp not found";
3801  return 0;
3802  }
3803 
3804  kXR_int32 dtim = hs->TimeStamp - tstamp;
3805  dtim = (dtim < 0) ? -dtim : dtim;
3806  if (dtim > skew) {
3807  emsg = "time difference too big: "; emsg += (int)dtim;
3808  emsg += " - allowed skew: "; emsg += skew;
3810  return 0;
3811  }
3813 
3814  DEBUG("Time stamp successfully checked");
3815 
3816  // Ok
3817  return 1;
3818 }
3819 
3820 //______________________________________________________________________________
3821 bool XrdSecProtocolpwd::CheckRtag(XrdSutBuffer *bm, String &emsg)
3822 {
3823  // Check random tag signature if it was sent with previous packet
3824  EPNAME("CheckRtag");
3825 
3826  // Make sure we got a buffer
3827  if (!bm) {
3828  emsg = "Buffer not defined";
3829  return 0;
3830  }
3831  //
3832  // If we sent out a random tag check it signature
3833  if (hs->Cref && hs->Cref->buf1.len > 0) {
3834  XrdSutBucket *brt = 0;
3835  if ((brt = bm->GetBucket(kXRS_signed_rtag))) {
3836  // Make suer we got a cipher
3837  if (!(hs->Hcip)) {
3838  emsg = "Session cipher undefined";
3839  return 0;
3840  }
3841  // Decrypt it with the session cipher
3842  if (!(hs->Hcip->Decrypt(*brt))) {
3843  emsg = "error decrypting random tag with session cipher";
3844  return 0;
3845  }
3846  } else {
3847  emsg = "random tag missing - protocol error";
3848  return 0;
3849  }
3850  //
3851  // Random tag cross-check: content
3852  if (memcmp(brt->buffer,hs->Cref->buf1.buf,hs->Cref->buf1.len)) {
3853  emsg = "random tag content mismatch";
3854  SafeDelete(hs->Cref);
3855  // Remove: should not be checked a second time
3856  return 0;
3857  }
3858  //
3859  // Reset the cache entry but we will not use the info a second time
3860  memset(hs->Cref->buf1.buf,0,hs->Cref->buf1.len);
3861  hs->Cref->buf1.SetBuf();
3862  //
3863  // Flag successful check
3864  hs->RtagOK = 1;
3866  DEBUG("Random tag successfully checked");
3867  } else {
3868  NOTIFY("Nothing to check");
3869  }
3870 
3871  // We are done
3872  return 1;
3873 }
int kXR_int32
Definition: XPtypes.hh:89
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
#define QTRACE(act)
Definition: XrdCmsTrace.hh:49
void XrdCryptoSetTrace(kXR_int32 trace)
Definition: XrdCryptoAux.cc:49
static XrdSysError eDest(0,"crypto_")
#define cryptoTRACE_Notify
Definition: XrdCryptoAux.hh:49
#define cryptoTRACE_Dump
Definition: XrdCryptoAux.hh:47
int(* XrdCryptoKDFunLen_t)()
Definition: XrdCryptoAux.hh:59
#define cryptoTRACE_Debug
Definition: XrdCryptoAux.hh:48
int(* XrdCryptoKDFun_t)(const char *pass, int plen, const char *salt, int slen, char *key, int klen)
Definition: XrdCryptoAux.hh:60
#define PRINT(y)
#define STR_NPOS
int stat(const char *path, struct stat *buf)
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)
#define close(a)
Definition: XrdPosix.hh:43
#define fopen(a, b)
Definition: XrdPosix.hh:49
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
#define SafeDelete(x)
#define REL2(x, y)
XrdOucString String
#define SafeDelArray(x)
#define XrdCryptoMax
#define XrdSecPROTOIDLEN
#define REL3(x, y, z)
#define XrdSecPROTOIDENT
#define XrdSecNOIPCHK
static const short kOptsChngPwd
static String NetRcRef
XrdVERSIONINFO(XrdSecProtocolpwdInit, secpwd)
char * XrdSecProtocolpwdInit(const char mode, const char *parms, XrdOucErrInfo *erp)
static const short kOptsAutoReg
static const char * pwdServerSteps[]
static const short kOptsUserPwd
static const short kOptsServer
static const int kOneDay
XrdOucTrace * pwdTrace
static String SrvPukRef
static const short kOptsExpCred
static const char * ServerStepStr(int ksrv)
static const kXR_int32 Version
static String ProtoID
static String UserRef
static const char * pwdClientSteps[]
XrdSecProtocol * XrdSecProtocolpwdObject(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
static const short kOptsAFSPwd
static const short kOptsCrypPwd
static const short kOptsVeriClt
#define POPTS(t, y)
static const char * gPWErrStr[]
static const short kOptsClntTty
static String Prefix
static const short kOptsVeriSrv
static String AdminRef
static const short kOptsAregAll
static const char * ClientStepStr(int kclt)
#define XrdSecpwdVERSION
@ kpCI_prompt
@ kpCI_exact
@ kpCI_undef
@ kpCI_wildcard
@ kpAR_none
@ kpAR_users
@ kPWErrParseBuffer
@ kPWErrBadOpt
@ kPWErrNoBuffer
@ kPWErrBadCreds
@ kPWErrSerialBuffer
@ kPWErrQueryCreds
@ kPWErrInit
@ kPWErrNoPublic
@ kPWErrDuplicateBucket
@ kPWErrBadProtocol
@ kPWErrNoUser
@ kPWErrCreateBucket
@ kPWErrLoadCrypto
@ kPWErrBadRndmTag
@ kPWErrDecodeBuffer
@ kPWErrError
@ kPWErrAddBucket
@ kpST_ok
@ kpST_more
@ kpST_error
@ kXPC_failureack
@ kXPC_autoreg
@ kXPC_reserved
@ kXPC_signedrtag
@ kXPC_normal
@ kXPC_creds
@ kXPC_verifysrv
@ kXPC_none
@ kpCT_afs
@ kpCT_old
@ kpCT_onetime
@ kpCT_normal
@ kpCT_new
@ kpCT_crypt
@ kpCT_undef
@ kpCT_afsenc
@ kXPS_puk
@ kXPS_credsreq
@ kXPS_failure
@ kXPS_reserved
@ kXPS_none
@ kXPS_init
@ kXPS_signedrtag
@ kXPS_newpuk
@ kXPS_rtag
#define TRACE_Authen
Definition: XrdSecTrace.hh:62
#define NOTIFY(y)
int ncrypt
XrdOucString DefCrypto
XrdOucString CryptList
XrdOucString File
XrdCryptoKDFunLen_t KDFunLen
XrdOucString SrvID
void ParseCrypto()
XrdCryptoKDFun_t KDFun
struct myOpts opts
int emsg(int rc, char *msg)
int XrdSutGetPass(const char *prompt, XrdOucString &passwd)
Definition: XrdSutAux.cc:156
int XrdSutParseTime(const char *tstr, int opt)
Definition: XrdSutAux.cc:540
int XrdSutExpand(XrdOucString &path)
Definition: XrdSutAux.cc:366
int XrdSutResolve(XrdOucString &path, const char *ho, const char *vo, const char *gr, const char *us)
Definition: XrdSutAux.cc:425
int XrdSutToHex(const char *in, int lin, char *out)
Definition: XrdSutAux.cc:241
const char * XrdSutHome()
Definition: XrdSutAux.cc:465
int XrdSutMkdir(const char *dir, unsigned int mode, const char *opt)
Definition: XrdSutAux.cc:493
const char * XrdSutBuckStr(int kbck)
Definition: XrdSutAux.cc:121
void XrdSutSetTrace(kXR_int32 trace)
Definition: XrdSutAux.cc:93
int XrdSutFromHex(const char *in, char *out, int &lout)
Definition: XrdSutAux.cc:274
int XrdSutGetLine(XrdOucString &line, const char *prompt)
Definition: XrdSutAux.cc:185
@ kXRS_user
Definition: XrdSutAux.hh:65
@ kXRS_signed_rtag
Definition: XrdSutAux.hh:64
@ kXRS_afsinfo
Definition: XrdSutAux.hh:84
@ kXRS_rtag
Definition: XrdSutAux.hh:63
@ kXRS_version
Definition: XrdSutAux.hh:71
@ kXRS_message
Definition: XrdSutAux.hh:68
@ kXRS_puk
Definition: XrdSutAux.hh:61
@ kXRS_timestamp
Definition: XrdSutAux.hh:78
@ kXRS_status
Definition: XrdSutAux.hh:72
@ kXRS_main
Definition: XrdSutAux.hh:58
@ kXRS_creds
Definition: XrdSutAux.hh:67
@ kXRS_cryptomod
Definition: XrdSutAux.hh:57
#define XrdSutMAXPPT
Definition: XrdSutAux.hh:49
#define sutTRACE_Notify
Definition: XrdSutAux.hh:100
#define sutTRACE_Debug
Definition: XrdSutAux.hh:99
#define sutTRACE_Dump
Definition: XrdSutAux.hh:98
@ kPFE_allowed
@ kPFE_disabled
@ kPFE_onetime
@ kPFE_ok
@ kPFE_expired
@ kPFE_crypt
#define kPFEopen
Definition: XrdSutPFile.hh:60
#define kPFEcreate
Definition: XrdSutPFile.hh:59
if(Avsz)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define ID
char * AsHexString()
virtual int Decrypt(const char *in, int lin, char *out)
virtual int Encrypt(const char *in, int lin, char *out)
virtual char * Public(int &lpub)
virtual bool Finalize(bool padded, char *pub, int lpub, const char *t)
virtual void SetTrace(kXR_int32 trace)
virtual XrdCryptoKDFun_t KDFun()
char * Name() const
virtual XrdCryptoCipher * Cipher(const char *t, int l=0)
virtual XrdCryptoKDFunLen_t KDFunLen()
static XrdCryptoFactory * GetCryptoFactory(const char *factoryname)
int setErrInfo(int code, const char *emsg)
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
bool endswith(char c)
bool beginswith(char c)
int erase(int start=0, int size=0)
int matches(const char *s, char wch=' *')
int rfind(const char c, int start=STR_NPOS)
int replace(const char *s1, const char *s2, int from=0, int to=-1)
int find(const char c, int start=0, bool forward=1)
int length() const
void append(const int i)
int tokenize(XrdOucString &tok, int from, char del=':')
void resize(int lmx=0)
char * GetToken(char **rest=0, int lowcase=0)
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
const char * tident
Trace identifier always preset.
Definition: XrdSecEntity.hh:81
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
XrdSecEntity Entity
XrdSecProtocolpwd(int opts, const char *hname, XrdNetAddrInfo &endPoint, const char *parms=0)
static char * Init(pwdOptions o, XrdOucErrInfo *erp)
void Delete()
Delete the protocol object. DO NOT use C++ delete() on this object.
int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)
XrdSecCredentials * getCredentials(XrdSecParameters *parm=0, XrdOucErrInfo *einfo=0)
static XrdOucTrace * EnableTracing()
XrdSutBucket * Next()
XrdSutBucket * Begin()
kXR_int32 type
Definition: XrdSutBucket.hh:46
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)
void ToString(XrdOucString &s)
void Update(char *nb=0, int ns=0, int ty=0)
Definition: XrdSutBucket.cc:95
int AddBucket(char *bp=0, int sz=0, int ty=0)
Definition: XrdSutBuffer.hh:59
int UpdateBucket(const char *bp, int sz, int ty)
void Message(const char *prepose=0)
int Serialized(char **buffer, char opt='n')
const char * GetOptions() const
Definition: XrdSutBuffer.hh:87
int GetNBuckets() const
Definition: XrdSutBuffer.hh:86
void SetStep(int s)
Definition: XrdSutBuffer.hh:90
void Dump(const char *stepstr=0, bool all=false)
int GetStep() const
Definition: XrdSutBuffer.hh:89
XrdSutBucket * GetBucket(kXR_int32 type, const char *tag=0)
kXR_int32 MarshalBucket(kXR_int32 type, kXR_int32 code)
const char * GetProtocol() const
Definition: XrdSutBuffer.hh:88
void Deactivate(kXR_int32 type)
kXR_int32 UnmarshalBucket(kXR_int32 type, kXR_int32 &code)
void SetBuf(const char *b=0, kXR_int32 l=0)
kXR_int32 len
int Flush(const char *pfname=0)
XrdSutPFEntry * Add(XrdSutPFCacheRef &urRef, const char *ID, bool force=0)
int Init(int capacity=100, bool lock=1)
void Dump(const char *msg=0)
int Load(const char *pfname)
kXR_int32 mtime
XrdSutPFBuf buf3
XrdSutPFBuf buf1
void SetName(const char *n=0)
XrdSutPFBuf buf2
XrdSutPFBuf buf4
bool IsValid() const
Definition: XrdSutPFile.hh:170
const char * Name() const
Definition: XrdSutPFile.hh:168
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
static int GetRndmTag(XrdOucString &rtag)
Definition: XrdSutRndm.cc:235
static char * GetBuffer(int len, int opt=-1)
Definition: XrdSutRndm.cc:179
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
bool Valid() const
Definition: XrdSysPriv.hh:92
XrdCryptoCipher * Hcip
XrdCryptoCipher * Rcip
XrdCryptoFactory * CF
XrdSutPFEntry * Pent
XrdSutPFEntry * Cref
XrdSutBuffer * Parms
void Print(XrdOucTrace *t)
XrdSysLogger Logger
Definition: XrdGlobals.cc:47
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.