XRootD
Loading...
Searching...
No Matches
XrdSecsssAdmin.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d S e c s s s A d m i n . c c */
4/* */
5/* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <cctype>
32#include <iostream>
33#include <limits.h>
34#include <cstdlib>
35#include <cstdio>
36#include <fcntl.h>
37#include <ctime>
38#include <sys/param.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41
43#include "XrdSys/XrdSysE2T.hh"
45#include "XrdSys/XrdSysTimer.hh"
46
48
49/******************************************************************************/
50/* D e f i n e s */
51/******************************************************************************/
52
53#define eMsg(x) std::cerr <<XrdpgmName <<": " <<x << std::endl
54
57 const char *Action;
58 const char *KeyName;
59 const char *KeyUser;
60 const char *KeyGrup;
61 const char *KeyFile;
62 time_t Expdt;
63 int Debug;
64 int Keep;
65 int KeyLen;
66 int KeyNum;
67 char Sort;
68
70 KeyGrup(0), KeyFile(0),
71 Expdt(0), Debug(0), Keep(3), KeyLen(32),
72 KeyNum(-1), Sort('k') {}
74};
75
76/******************************************************************************/
77/* G l o b a l s */
78/******************************************************************************/
79
80static const char *XrdpgmName;
81
82/******************************************************************************/
83/* m a i n */
84/******************************************************************************/
85
86int main(int argc, char **argv)
87{
88 extern char *optarg;
89 extern int optopt, optind, opterr;
94 extern time_t getXDate(const char *cDate);
95 extern void Usage(int rc, const char *opn=0, const char *opv=0);
96
98 enum What2Do {doAdd, doInst, doDel, doList};
99 char c, *sp;
100 const char *validOpts = "dg:h:k:l:n:s:u:x:";
101 int rc;
102 What2Do doIt = doList;
103
104// Get the name of our program
105//
106 XrdpgmName = ((sp = rindex(argv[0], '/')) ? sp+1 : argv[0]);
107
108// Process the options
109//
110 opterr = 0;
111 if (argc > 1 && '-' == *argv[1])
112 while ((c = getopt(argc,argv,validOpts))
113 && ((unsigned char)c != 0xff))
114 { switch(c)
115 {
116 case 'd': Opt.Debug = 1;
117 break;
118 case 'g': Opt.KeyGrup = optarg;
119 break;
120 case 'h': if ((Opt.Keep = atoi(optarg)) <= 0) Usage(1, "-s", optarg);
121 break;
122 case 'k': Opt.KeyName = optarg;
123 break;
124 case 'l': if ((Opt.KeyLen = atoi(optarg)) <= 0
126 Usage(1, "-l", optarg);
127 break;
128 case 'n': if ((Opt.KeyNum = atoi(optarg)) <= 0) Usage(1, "-n", optarg);
129 break;
130 case 's': if ((int)strlen(optarg) > 1 || !index("cgknux", *optarg))
131 Usage(1, "-s", optarg);
132 Opt.Sort = *optarg;
133 break;
134 case 'u': Opt.KeyUser = optarg;
135 break;
136 case 'x': if ((Opt.Expdt = getXDate(optarg)) < 0
137 || Opt.Expdt < (time(0)+60)) Usage(1, "-x", optarg);
138 break;
139 default: if (index(validOpts, optopt)) Usage(1, argv[optind-1], optarg);
140 else {eMsg("Invalid option '" <<argv[optind-1] <<"'");
141 Usage(1);
142 }
143 }
144 }
145
146// Make sure and opreration has been specified
147//
148 if (optind >= argc) {eMsg("Action not specified."); Usage(1);}
149
150// Verify the action
151//
152 if (!strcmp(argv[optind], "add")) doIt = doAdd;
153 else if (!strcmp(argv[optind], "install")) doIt = doInst;
154 else if (!strcmp(argv[optind], "del")) doIt = doDel;
155 else if (!strcmp(argv[optind], "list")) doIt = doList;
156 else Usage(1, "parameter", argv[optind]);
157 Opt.Action = argv[optind++];
158
159// Make sure keyname is not too long
160//
161 if (Opt.KeyName && (int)strlen(Opt.KeyName) >= XrdSecsssKT::ktEnt::NameSZ)
162 {eMsg("Key name must be less than " <<XrdSecsssKT::ktEnt::NameSZ
163 << " characters.");
164 exit(4);
165 }
166
167// Make sure username is not too long
168//
169 if (Opt.KeyUser && (int)strlen(Opt.KeyUser) >= XrdSecsssKT::ktEnt::UserSZ)
170 {eMsg("User name must be less than " <<XrdSecsssKT::ktEnt::UserSZ
171 << " characters.");
172 exit(4);
173 }
174
175// Make sure group name is not too long
176//
177 if (Opt.KeyGrup && (int)strlen(Opt.KeyGrup) >= XrdSecsssKT::ktEnt::GrupSZ)
178 {eMsg("group name must be less than " <<XrdSecsssKT::ktEnt::GrupSZ
179 << " characters.");
180 exit(4);
181 }
182
183// Provide default keyfile if none specified
184//
185 if (optind < argc) Opt.KeyFile = argv[optind++];
186 else Opt.KeyFile = XrdSecsssKT::genFN();
187
188// Perform the action
189//
190 switch(doIt)
191 {case doAdd: rc = XrdSecsssAdmin_addKey(Opt); break;
192 case doDel: rc = XrdSecsssAdmin_delKey(Opt); break;
193 case doInst: rc = XrdSecsssAdmin_insKey(Opt); break;
194 case doList: rc = XrdSecsssAdmin_lstKey(Opt); break;
195 default: rc = 16; eMsg("Internal processing error!");
196 }
197
198// All done
199//
200 if (Opt.kTab) delete Opt.kTab;
201 exit(rc);
202}
203
204/******************************************************************************/
205/* g e t X D a t e */
206/******************************************************************************/
207
208time_t getXDate(const char *cDate)
209{
210 struct tm myTM;
211 char *eP;
212 long theVal;
213
214// if no slashes then this is number of days
215//
216 if (!index(cDate, '/'))
217 {theVal = strtol(cDate, &eP, 10);
218 if (errno || *eP) return -1;
219 if (theVal) theVal = XrdSysTimer::Midnight() + (86400*theVal);
220 return static_cast<time_t>(theVal);
221 }
222
223// Do a date conversion
224//
225 eP = strptime(cDate, "%D", &myTM);
226 if (*eP) return -1;
227 return mktime(&myTM);
228}
229
230/******************************************************************************/
231/* i s N o */
232/******************************************************************************/
233
234int isNo(int dflt, const char *Msg1, const char *Msg2, const char *Msg3)
235{
236 char Answer[8];
237
238 std::cerr <<XrdpgmName <<": " <<Msg1 <<Msg2 <<Msg3;
239 std::cin.getline(Answer, sizeof(Answer));
240 if (!*Answer) return dflt;
241
242 if (!strcmp("y",Answer) || !strcmp("ye",Answer) || !strcmp("yes",Answer))
243 return 0;
244 return 1;
245}
246
247/******************************************************************************/
248/* U s a g e */
249/******************************************************************************/
250
251void Usage(int rc, const char *opn, const char *opv)
252{
253// Check if we need to issue a message here
254//
255 if (opn)
256 {if (opv) eMsg("Invalid " <<opn <<" argument - " <<opv);
257 else eMsg(opn <<" argument not specified.");
258 }
259
260std::cerr <<"\nUsage: " <<XrdpgmName <<" [options] action\n";
261std::cerr <<"\nOptions: [-d] [-g grpname] [-h hold] [-k keyname] [-l keylen] [-n keynum]";
262std::cerr <<"\n [-s {c|g|k|n|u|x}] [-u usrname] [-x {days | mm/dd/yy}]" <<std::endl;
263std::cerr <<"\nActions: {add | del | install | list} [keyfn]" <<std::endl;
264exit(rc);
265}
266
267/******************************************************************************/
268/* X r d S e c s s s A d m i n _ a d d K e y */
269/******************************************************************************/
270
272{
273 XrdOucErrInfo eInfo;
274 XrdSecsssKT::ktEnt *ktEnt;
275 int retc, numKeys, numTot, numExp;
276
277// Allocate the initial keytab
278//
279 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
280 if ((retc = eInfo.getErrInfo()))
281 {if (retc != ENOENT || isNo(0, "Keyfile '", Opt.KeyFile,
282 "' does not exist. Create it? (y | n): ")) return 4;
283 }
284
285// Construct a new KeyTab entry
286//
287 ktEnt = new XrdSecsssKT::ktEnt;
288 strcpy(ktEnt->Data.Name, (Opt.KeyName ? Opt.KeyName : "nowhere"));
289 strcpy(ktEnt->Data.User, (Opt.KeyUser ? Opt.KeyUser : "nobody"));
290 strcpy(ktEnt->Data.Grup, (Opt.KeyGrup ? Opt.KeyGrup : "nogroup"));
293 else if (Opt.KeyLen < 4) ktEnt->Data.Len = 4;
294 else ktEnt->Data.Len = Opt.KeyLen/4*4;
295 ktEnt->Data.Exp = Opt.Expdt;
296 Opt.kTab->addKey(*ktEnt);
297
298// Now rewrite the file
299//
300 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
301 {eMsg("Unable to add key to '" <<Opt.KeyFile <<"'; " <<XrdSysE2T(retc));
302 retc = 8;
303 } else {
304 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
305 <<numTot <<" kept (" <<numExp <<" expired).");
306 }
307
308// All done
309//
310 return retc;
311}
312
313/******************************************************************************/
314/* X r d S e c s s s A d m i n _ d e l K e y */
315/******************************************************************************/
316
318{
319 XrdOucErrInfo eInfo;
320 XrdSecsssKT::ktEnt ktEnt;
321 int retc, numKeys, numTot, numExp, numDel;
322
323// Allocate the initial keytab
324//
325 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
326 if ((retc = eInfo.getErrInfo()))
327 {if (retc == ENOENT)
328 {eMsg("Keyfile '" <<Opt.KeyFile <<"' does not exist.");}
329 return 4;
330 }
331
332// Construct deletion reference
333//
334 if (Opt.KeyName) strcpy(ktEnt.Data.Name, Opt.KeyName);
335 if (Opt.KeyUser) strcpy(ktEnt.Data.User, Opt.KeyUser);
336 if (Opt.KeyGrup) strcpy(ktEnt.Data.Grup, Opt.KeyGrup);
337 ktEnt.Data.ID = static_cast<long long>(Opt.KeyNum);
338
339// Delete the keys from the key table
340//
341 if (!(numDel = Opt.kTab->delKey(ktEnt)))
342 {eMsg("No matching key(s) found.");
343 return 4;
344 }
345
346// It's possible that all of the keys were deleted. Check for that
347//
348 if (Opt.kTab->keyList() == 0)
349 {if (isNo(1, "No keys will remain in ", Opt.KeyFile,
350 ". Delete file? (n | y): "))
351 {eMsg("No keys deleted!"); return 2;}
352 unlink(Opt.KeyFile);
353 return 0;
354 }
355
356// Now rewrite the file
357//
358 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
359 {eMsg("Unable to del key from '" <<Opt.KeyFile <<"'; " <<XrdSysE2T(retc));
360 retc = 8;
361 } else {
362 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
363 <<(numTot+numDel) <<" kept (" <<numExp <<" expired).");
364 }
365
366// All done
367//
368 return retc;
369}
370
371/******************************************************************************/
372/* X r d S e c s s s A d m i n _ i n s K e y */
373/******************************************************************************/
374
376{
378 XrdSecsssKT::ktEnt *ktP);
379 XrdOucErrInfo eInfo;
381 int retc, numKeys = 0, numTot, numExp;
382
383// Allocate the initial keytab
384//
385 Opt.kTab = new XrdSecsssKT(&eInfo, 0, XrdSecsssKT::isAdmin);
386 if ((retc = eInfo.getErrInfo())) return 4;
387
388// Check if we need to trim the keytab to a particular key
389//
390 if (Opt.KeyName || Opt.KeyUser || Opt.KeyGrup)
391 {ktP = Opt.kTab->keyList();
392 while(ktP)
393 {if (!XrdSecsssAdmin_isKey(Opt, ktP)) ktP->Data.Name[0] = '\0';
394 else numKeys++;
395 ktP = ktP->Next;
396 }
397 if (!numKeys)
398 {eMsg("No keys named " <<Opt.KeyName <<" found to install.");
399 return 8;
400 }
401 }
402
403// Now rewrite the file
404//
405 Opt.kTab->setPath(Opt.KeyFile);
406 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
407 {eMsg("Unable to install keytab '" <<Opt.KeyFile <<"'; " <<XrdSysE2T(retc));
408 retc = 8;
409 } else {
410 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
411 <<numTot <<" installed (" <<numExp <<" expired).");
412 }
413
414// All done
415//
416 return retc;
417}
418
419/******************************************************************************/
420/* X r d S e c s s s A d m i n _ i s K e y */
421/******************************************************************************/
422
425{
426 if (Opt.KeyName && strcmp(ktP->Data.Name, Opt.KeyName)) return 0;
427 if (Opt.KeyUser && strcmp(ktP->Data.User, Opt.KeyUser)) return 0;
428 if (Opt.KeyGrup && strcmp(ktP->Data.Grup, Opt.KeyGrup)) return 0;
429 return 1;
430}
431
432/******************************************************************************/
433/* X r d S e c s s s A d m i n _ H e r e */
434/******************************************************************************/
435
438{
439 int n;
440 char *sf1, *sf2;
441
442 switch(sType)
443 {case 'c': return ktX->Data.Crt < ktS->Data.Crt;
444 case 'g': sf1 = ktX->Data.Grup; sf2 = ktS->Data.Grup; break;
445 case 'k': sf1 = ktX->Data.Name; sf2 = ktS->Data.Name; break;
446 case 'n': return (ktX->Data.ID & 0x7fffffff) < (ktS->Data.ID & 0x7fffffff);
447 case 'u': sf1 = ktX->Data.User; sf2 = ktS->Data.User; break;
448 case 'x': return ktX->Data.Exp < ktS->Data.Exp;
449 default: return 0;
450 }
451
452 if ((n = strcmp(sf1, sf2))) return n < 0;
453 return (ktX->Data.ID & 0x7fffffff) < (ktS->Data.ID & 0x7fffffff);
454}
455
456/******************************************************************************/
457/* X r d S e c s s s A d m i n _ l s t K e y */
458/******************************************************************************/
459
461{
462 static const char Hdr1[] =
463 " Number Len Date/Time Created Expires Keyname User & Group\n";
464// 12345678901 123 mm/dd/yy hh:mm:ss mm/dd/yy
465 static const char Hdr2[] =
466 " ------ --- --------- ------- -------- -------\n";
467
469 XrdSecsssKT::ktEnt *ktP);
470 XrdOucErrInfo eInfo;
471 XrdSecsssKT::ktEnt *ktP, *ktSort = 0, *ktS, *ktSP, *ktX;
472 char crfmt[] = "%D %T", exfmt[] = "%D";
473 char buff[128], crbuff[64], exbuff[16];
474 int retc, pHdr = 1;
475
476// Allocate the initial keytab
477//
478 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
479 if ((retc = eInfo.getErrInfo()))
480 {if (retc == ENOENT)
481 {eMsg("Keyfile '" <<Opt.KeyFile <<"' does not exist.");}
482 return 4;
483 }
484
485// Obtain the keytab list
486//
487 if ((ktP = Opt.kTab->keyList()))
488 {ktSort = ktP; ktP = ktP->Next; ktSort->Next = 0;}
489
490// Sort the list
491//
492 while(ktP)
493 {ktS = ktSort; ktSP = 0; ktX = ktP; ktP = ktP->Next; ktX->Next = 0;
494 while(ktS)
495 {if (XrdSecsssAdmin_Here(Opt.Sort, ktX, ktS))
496 {if (ktSP) {ktX->Next = ktS; ktSP->Next = ktX;}
497 else {ktX->Next = ktSort; ktSort = ktX;}
498 break;
499 }
500 ktSP = ktS; ktS = ktS->Next;
501 }
502 if (!ktS) ktSP->Next = ktX;
503 }
504
505// List the keys
506//
507 ktP = ktSort;
508 while(ktP)
509 {if (XrdSecsssAdmin_isKey(Opt, ktP))
510 {if (pHdr) {std::cout <<Hdr1 <<Hdr2; pHdr = 0;}
511 sprintf(buff, "%11lld %3d ", (ktP->Data.ID & 0x7fffffff), ktP->Data.Len);
512 strftime(crbuff, sizeof(crbuff), crfmt, localtime(&ktP->Data.Crt));
513 if (!ktP->Data.Exp) strcpy(exbuff, "--------");
514 else strftime(exbuff,sizeof(exbuff),exfmt,localtime(&ktP->Data.Exp));
515 std::cout <<buff <<crbuff <<' ' <<exbuff <<' ' <<ktP->Data.Name <<' '
516 <<ktP->Data.User <<' ' <<ktP->Data.Grup <<std::endl;
517 }
518 ktP = ktP->Next;
519 }
520
521// Check if we printed anything
522//
523 if (pHdr)
524 {if (Opt.KeyName) eMsg(Opt.KeyName <<" key not found in " <<Opt.KeyFile);
525 else eMsg("No keys found in " <<Opt.KeyFile);
526 }
527 return 0;
528}
529
530
int optopt
int optind
#define unlink(a)
Definition XrdPosix.hh:108
int XrdSecsssAdmin_insKey(XrdsecsssAdmin_Opts &Opt)
int main(int argc, char **argv)
int XrdSecsssAdmin_Here(char sType, XrdSecsssKT::ktEnt *ktX, XrdSecsssKT::ktEnt *ktS)
int isNo(int dflt, const char *Msg1, const char *Msg2, const char *Msg3)
int XrdSecsssAdmin_isKey(XrdsecsssAdmin_Opts &Opt, XrdSecsssKT::ktEnt *ktP)
static const char * XrdpgmName
int XrdSecsssAdmin_lstKey(XrdsecsssAdmin_Opts &Opt)
int XrdSecsssAdmin_addKey(XrdsecsssAdmin_Opts &Opt)
time_t getXDate(const char *cDate)
int XrdSecsssAdmin_delKey(XrdsecsssAdmin_Opts &Opt)
#define eMsg(x)
void Usage(int rc, const char *opn, const char *opv)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
static const int UserSZ
struct XrdSecsssKT::ktEnt::ktData Data
static const int GrupSZ
static const int maxKLen
static const int NameSZ
void setPath(const char *Path)
int delKey(ktEnt &ktDel)
int Rewrite(int Keep, int &numKeys, int &numTot, int &numExp)
static char * genFN()
ktEnt * keyList()
void addKey(ktEnt &ktNew)
static time_t Midnight(time_t tnow=0)