XRootD
Loading...
Searching...
No Matches
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
46#include "XrdSys/XrdSysError.hh"
47#include "XrdSys/XrdSysPwd.hh"
49
50#include "XrdSys/XrdSysPriv.hh"
51
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
70static String Prefix = "xrd";
73static String AdminRef = ProtoID + "admin";
74static String SrvPukRef= ProtoID + "srvpuk";
75static String UserRef = ProtoID + "user";
76static String NetRcRef = ProtoID + "netrc";
77
78static 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
89static 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
101static 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
143static const short kOptsServer = 0x0001;
144static const short kOptsUserPwd = 0x0002;
145static const short kOptsAutoReg = 0x0004;
146static const short kOptsAregAll = 0x0008;
147static const short kOptsVeriSrv = 0x0020;
148static const short kOptsVeriClt = 0x0040;
149static const short kOptsClntTty = 0x0080;
150static const short kOptsExpCred = 0x0100;
151static const short kOptsCrypPwd = 0x0200;
152static const short kOptsChngPwd = 0x0400;
153static const short kOptsAFSPwd = 0x0800;
154// One day in secs
155static const int kOneDay = 86400;
156
157/******************************************************************************/
158/* S t a t i c C l a s s D a t a */
159/******************************************************************************/
160XrdSysMutex XrdSecProtocolpwd::pwdContext;
161String XrdSecProtocolpwd::FileAdmin= "";
162String XrdSecProtocolpwd::FileExpCreds= "";
163String XrdSecProtocolpwd::FileUser = "";
164String XrdSecProtocolpwd::FileCrypt= "/.xrdpass";
165String XrdSecProtocolpwd::FileSrvPuk= "";
166String XrdSecProtocolpwd::SrvID = "";
167String XrdSecProtocolpwd::SrvEmail = "";
168String XrdSecProtocolpwd::DefCrypto= "ssl";
169String XrdSecProtocolpwd::DefError = "insufficient credentials - contact ";
170XrdSutPFile XrdSecProtocolpwd::PFAdmin(0); // Admin file (server)
171XrdSutPFile XrdSecProtocolpwd::PFAlog(0); // Autologin file (client)
172XrdSutPFile XrdSecProtocolpwd::PFSrvPuk(0); // File with server public keys (client)
173//
174// Crypto related info
175int XrdSecProtocolpwd::ncrypt = 0; // Number of factories
176int XrdSecProtocolpwd::cryptID[XrdCryptoMax] = {0}; // their IDs
177String XrdSecProtocolpwd::cryptName[XrdCryptoMax] = {0}; // their names
178XrdCryptoCipher *XrdSecProtocolpwd::refcip[XrdCryptoMax] = {0}; // ref for session ciphers
179//
180// Caches for info files
181XrdSutPFCache XrdSecProtocolpwd::cacheAdmin; // Admin file
182XrdSutPFCache XrdSecProtocolpwd::cacheSrvPuk; // SrvPuk file
183XrdSutPFCache XrdSecProtocolpwd::cacheUser; // User files
184XrdSutPFCache XrdSecProtocolpwd::cacheAlog; // Autologin file
185//
186// Running options / settings
187int XrdSecProtocolpwd::Debug = 0; // [CS] Debug level
188bool XrdSecProtocolpwd::Server = 1; // [CS] If server mode
189int XrdSecProtocolpwd::UserPwd = 0; // [S] Check passwd file in user's <xrdsecdir>
190bool XrdSecProtocolpwd::SysPwd = 0; // [S] Check passwd file in user's <xrdsecdir>
191int XrdSecProtocolpwd::VeriClnt = 2; // [S] Client authenticity verification level:
192 // 0 none, 1 timestamp, 2 random tag
193int XrdSecProtocolpwd::VeriSrv = 1; // [C] Server authenticity verification level:
194 // 0 none, 1 random tag
195int XrdSecProtocolpwd::AutoReg = kpAR_none; // [S] Autoreg mode
196int XrdSecProtocolpwd::LifeCreds = 0; // [S] if > 0, time interval of validity for creds
197int XrdSecProtocolpwd::MaxPrompts = 3; // [C] Repeating prompt
198int XrdSecProtocolpwd::MaxFailures = 10;// [S] Max passwd failures before blocking
199int XrdSecProtocolpwd::AutoLogin = 0; // [C] do-not-check/check/update autologin info
200int XrdSecProtocolpwd::TimeSkew = 300; // [CS] Allowed skew in secs for time stamps
201bool XrdSecProtocolpwd::KeepCreds = 0; // [S] Keep / Do-Not-Keep client creds
202int XrdSecProtocolpwd::FmtExpCreds = 0; // [S] Format for exported credentials
203//
204// Debug an tracing
205XrdSysError XrdSecProtocolpwd::eDest(0, "secpwd_");
206XrdSysLogger XrdSecProtocolpwd::Logger;
207XrdOucTrace *XrdSecProtocolpwd::PWDTrace = 0;
208
210
211/******************************************************************************/
212/* S t a t i c F u n c t i o n s */
213/******************************************************************************/
214//_____________________________________________________________________________
215static 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//_____________________________________________________________________________
231static 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();
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)
999if (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:
1018if ((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;
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:
1360if (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
1675extern "C"
1676{
1677char *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
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
1901extern "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//__________________________________________________________________________
1935int 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
1994 if ((hs->CF = XrdCryptoFactory::GetCryptoFactory(hs->CryptoMod.c_str()))) {
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//____________________________________________________________________
2025bool 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//________________________________________________________________________
2107bool XrdSecProtocolpwd::CheckCredsAFS(XrdSutBucket *, int)
2108{
2109 // Check AFS credentials - not supported
2110 return 0;
2111}
2112
2113//____________________________________________________________________
2114int 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//____________________________________________________________________
2175int 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//____________________________________________________________________
2315XrdSutBucket *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
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//____________________________________________________________________
2622int 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//____________________________________________________________________
2668int 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//_________________________________________________________________________
2872int 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//_________________________________________________________________________
2912int 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//_________________________________________________________________________
3022int 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//_________________________________________________________________________
3244int 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//__________________________________________________________________
3358void 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//__________________________________________________________________
3413XrdSecCredentials *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//__________________________________________________________________
3435int 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//_______________________________________________________________________
3454int 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
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//______________________________________________________________________________
3536int 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//______________________________________________________________________________
3676int 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//______________________________________________________________________________
3770bool 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//______________________________________________________________________________
3821bool 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)
#define EPNAME(x)
#define TRACE_Debug
#define QTRACE(act)
void XrdCryptoSetTrace(kXR_int32 trace)
#define cryptoTRACE_Notify
#define cryptoTRACE_Dump
int(* XrdCryptoKDFunLen_t)()
#define cryptoTRACE_Debug
int(* XrdCryptoKDFun_t)(const char *pass, int plen, const char *salt, int slen, char *key, int klen)
#define PRINT(y)
#define STR_NPOS
int fclose(FILE *stream)
#define close(a)
Definition XrdPosix.hh:43
#define fopen(a, b)
Definition XrdPosix.hh:49
#define write(a, b, c)
Definition XrdPosix.hh:110
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
#define read(a, b, c)
Definition XrdPosix.hh:77
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
static const int kOneDay
static const char * ClientStepStr(int kclt)
static const kXR_int32 Version
static const char * ServerStepStr(int ksrv)
static String ProtoID
#define POPTS(t, y)
static String Prefix
XrdOucString String
#define XrdCryptoMax
#define XrdSecPROTOIDENT
#define XrdSecNOIPCHK
static const short kOptsChngPwd
static String NetRcRef
XrdVERSIONINFO(XrdSecProtocolpwdInit, secpwd)
static const short kOptsAutoReg
static const char * pwdServerSteps[]
static const short kOptsUserPwd
static const short kOptsServer
XrdOucTrace * pwdTrace
static String SrvPukRef
static const short kOptsExpCred
static const char * ClientStepStr(int kclt)
char * XrdSecProtocolpwdInit(const char mode, const char *parms, XrdOucErrInfo *erp)
static const char * ServerStepStr(int ksrv)
static String UserRef
static const char * pwdClientSteps[]
static const short kOptsAFSPwd
static const short kOptsCrypPwd
static const short kOptsVeriClt
XrdSecProtocol * XrdSecProtocolpwdObject(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
static const char * gPWErrStr[]
static const short kOptsClntTty
static const short kOptsVeriSrv
static String AdminRef
static const short kOptsAregAll
#define SafeDelete(x)
#define XrdSecpwdVERSION
@ kpCI_prompt
@ kpCI_exact
@ kpCI_undef
@ kpCI_wildcard
#define REL2(x, y)
@ 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
#define SafeDelArray(x)
#define XrdCryptoMax
#define XrdSecPROTOIDLEN
@ kpCT_onetime
@ kpCT_normal
@ kpCT_crypt
@ kpCT_undef
@ kpCT_afsenc
#define REL3(x, y, z)
#define XrdSecPROTOIDENT
@ kXPS_credsreq
@ kXPS_failure
@ kXPS_reserved
@ kXPS_none
@ kXPS_init
@ kXPS_signedrtag
@ kXPS_newpuk
@ kXPS_rtag
#define TRACE_Authen
#define NOTIFY(y)
XrdOucString CryptList
XrdOucString File
XrdCryptoKDFunLen_t KDFunLen
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
int XrdSutMkdir(const char *dir, unsigned int mode, const char *opt)
Definition XrdSutAux.cc:493
const char * XrdSutHome()
Definition XrdSutAux.cc:465
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
#define kPFEcreate
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE_ALL
Definition XrdTrace.hh:35
#define ID
virtual int Encrypt(const char *in, int lin, char *out)
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)
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)
const char * c_str() const
char * GetToken(char **rest=0, int lowcase=0)
XrdSecEntity Entity
XrdSecProtocol(const char *pName)
Constructor.
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
kXR_int32 size
int SetBuf(const char *nb=0, int ns=0)
void ToString(XrdOucString &s)
void Update(char *nb=0, int ns=0, int ty=0)
int AddBucket(char *bp=0, int sz=0, int ty=0)
int UpdateBucket(const char *bp, int sz, int ty)
void Message(const char *prepose=0)
int Serialized(char **buffer, char opt='n')
int GetNBuckets() const
void SetStep(int s)
const char * GetProtocol() const
void Dump(const char *stepstr=0, bool all=false)
const char * GetOptions() const
int GetStep() const
XrdSutBucket * GetBucket(kXR_int32 type, const char *tag=0)
kXR_int32 MarshalBucket(kXR_int32 type, kXR_int32 code)
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
kXR_int32 mtime
XrdSutPFBuf buf1
void SetName(const char *n=0)
XrdSutPFBuf buf2
static int GetRndmTag(XrdOucString &rtag)
static char * GetBuffer(int len, int opt=-1)
bool Valid() const
Definition XrdSysPriv.hh:92
void Print(XrdOucTrace *t)
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.