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