00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdSecsssAdminCVSID = "$Id: XrdSecsssAdmin.cc 27487 2009-02-18 13:17:34Z ganis $";
00014
00015 #include <ctype.h>
00016 #include <limits.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <time.h>
00022 #include <sys/param.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025
00026 #include "XrdOuc/XrdOucErrInfo.hh"
00027 #include "XrdSys/XrdSysHeaders.hh"
00028 #include "XrdSys/XrdSysPlatform.hh"
00029 #include "XrdSys/XrdSysTimer.hh"
00030
00031 #include "XrdSecsss/XrdSecsssKT.hh"
00032
00033
00034
00035
00036
00037 #define eMsg(x) cerr <<XrdpgmName <<": " <<x << endl
00038
00039 struct XrdsecsssAdmin_Opts
00040 {XrdSecsssKT *kTab;
00041 const char *Action;
00042 const char *KeyName;
00043 const char *KeyUser;
00044 const char *KeyGrup;
00045 const char *KeyFile;
00046 time_t Expdt;
00047 int Debug;
00048 int Keep;
00049 int KeyLen;
00050 int KeyNum;
00051 char Sort;
00052
00053 XrdsecsssAdmin_Opts() : kTab(0), Action(0), KeyName(0), KeyUser(0),
00054 KeyGrup(0), KeyFile(0),
00055 Expdt(0), Debug(0), Keep(3), KeyLen(32),
00056 KeyNum(-1), Sort('k') {}
00057 ~XrdsecsssAdmin_Opts() {}
00058 };
00059
00060
00061
00062
00063
00064 static const char *XrdpgmName;
00065
00066
00067
00068
00069
00070 int main(int argc, char **argv)
00071 {
00072 extern char *optarg;
00073 extern int optopt, optind, opterr;
00074 extern int XrdSecsssAdmin_addKey(XrdsecsssAdmin_Opts &Opt);
00075 extern int XrdSecsssAdmin_delKey(XrdsecsssAdmin_Opts &Opt);
00076 extern int XrdSecsssAdmin_insKey(XrdsecsssAdmin_Opts &Opt);
00077 extern int XrdSecsssAdmin_lstKey(XrdsecsssAdmin_Opts &Opt);
00078 extern time_t getXDate(const char *cDate);
00079 extern void Usage(int rc, const char *opn=0, const char *opv=0);
00080
00081 XrdsecsssAdmin_Opts Opt;
00082 enum What2Do {doAdd, doInst, doDel, doList};
00083 char c, *sp;
00084 const char *validOpts = "dg:h:k:l:n:s:u:x:";
00085 int rc;
00086 What2Do doIt = doList;
00087
00088
00089
00090 XrdpgmName = ((sp = rindex(argv[0], '/')) ? sp+1 : argv[0]);
00091
00092
00093
00094 opterr = 0;
00095 if (argc > 1 && '-' == *argv[1])
00096 while ((c = getopt(argc,argv,validOpts))
00097 && ((unsigned char)c != 0xff))
00098 { switch(c)
00099 {
00100 case 'd': Opt.Debug = 1;
00101 break;
00102 case 'g': Opt.KeyGrup = optarg;
00103 break;
00104 case 'h': if ((Opt.Keep = atoi(optarg)) <= 0) Usage(1, "-s", optarg);
00105 break;
00106 case 'k': Opt.KeyName = optarg;
00107 break;
00108 case 'l': if ((Opt.KeyLen = atoi(optarg)) <= 0
00109 || Opt.KeyLen > XrdSecsssKT::ktEnt::maxKLen)
00110 Usage(1, "-l", optarg);
00111 break;
00112 case 'n': if ((Opt.KeyNum = atoi(optarg)) <= 0) Usage(1, "-n", optarg);
00113 break;
00114 case 's': if ((int)strlen(optarg) > 1 || !index("cgknux", *optarg))
00115 Usage(1, "-s", optarg);
00116 Opt.Sort = *optarg;
00117 break;
00118 case 'u': Opt.KeyUser = optarg;
00119 break;
00120 case 'x': if ((Opt.Expdt = getXDate(optarg)) < 0
00121 || Opt.Expdt < (time(0)+60)) Usage(1, "-x", optarg);
00122 break;
00123 default: if (index(validOpts, optopt)) Usage(1, argv[optind-1], optarg);
00124 else {eMsg("Invalid option '" <<argv[optind-1] <<"'");
00125 Usage(1);
00126 }
00127 }
00128 }
00129
00130
00131
00132 if (optind >= argc) {eMsg("Action not specified."); Usage(1);}
00133
00134
00135
00136 if (!strcmp(argv[optind], "add")) doIt = doAdd;
00137 else if (!strcmp(argv[optind], "install")) doIt = doInst;
00138 else if (!strcmp(argv[optind], "del")) doIt = doDel;
00139 else if (!strcmp(argv[optind], "list")) doIt = doList;
00140 else Usage(1, "parameter", argv[optind]);
00141 Opt.Action = argv[optind++];
00142
00143
00144
00145 if (Opt.KeyName && (int)strlen(Opt.KeyName) >= XrdSecsssKT::ktEnt::NameSZ)
00146 {eMsg("Key name must be less than " <<XrdSecsssKT::ktEnt::NameSZ
00147 << " characters.");
00148 exit(4);
00149 }
00150
00151
00152
00153 if (Opt.KeyUser && (int)strlen(Opt.KeyUser) >= XrdSecsssKT::ktEnt::UserSZ)
00154 {eMsg("User name must be less than " <<XrdSecsssKT::ktEnt::UserSZ
00155 << " characters.");
00156 exit(4);
00157 }
00158
00159
00160
00161 if (Opt.KeyGrup && (int)strlen(Opt.KeyGrup) >= XrdSecsssKT::ktEnt::GrupSZ)
00162 {eMsg("group name must be less than " <<XrdSecsssKT::ktEnt::GrupSZ
00163 << " characters.");
00164 exit(4);
00165 }
00166
00167
00168
00169 if (optind < argc) Opt.KeyFile = argv[optind++];
00170 else Opt.KeyFile = XrdSecsssKT::genFN();
00171
00172
00173
00174 switch(doIt)
00175 {case doAdd: rc = XrdSecsssAdmin_addKey(Opt); break;
00176 case doDel: rc = XrdSecsssAdmin_delKey(Opt); break;
00177 case doInst: rc = XrdSecsssAdmin_insKey(Opt); break;
00178 case doList: rc = XrdSecsssAdmin_lstKey(Opt); break;
00179 default: rc = 16; eMsg("Internal processing error!");
00180 }
00181
00182
00183
00184 if (Opt.kTab) delete Opt.kTab;
00185 exit(rc);
00186 }
00187
00188
00189
00190
00191
00192 time_t getXDate(const char *cDate)
00193 {
00194 struct tm myTM;
00195 char *eP;
00196 long theVal;
00197
00198
00199
00200 if (!index(cDate, '/'))
00201 {theVal = strtol(cDate, &eP, 10);
00202 if (errno || *eP) return -1;
00203 if (theVal) theVal = XrdSysTimer::Midnight() + (86400*theVal);
00204 return static_cast<time_t>(theVal);
00205 }
00206
00207
00208
00209 eP = strptime(cDate, "%D", &myTM);
00210 if (*eP) return -1;
00211 return mktime(&myTM);
00212 }
00213
00214
00215
00216
00217
00218 int isNo(int dflt, const char *Msg1, const char *Msg2, const char *Msg3)
00219 {
00220 char Answer[8];
00221
00222 cerr <<XrdpgmName <<": " <<Msg1 <<Msg2 <<Msg3;
00223 cin.getline(Answer, sizeof(Answer));
00224 if (!*Answer) return dflt;
00225
00226 if (!strcmp("y",Answer) || !strcmp("ye",Answer) || !strcmp("yes",Answer))
00227 return 0;
00228 return 1;
00229 }
00230
00231
00232
00233
00234
00235 void Usage(int rc, const char *opn, const char *opv)
00236 {
00237
00238
00239 if (opn)
00240 {if (opv) eMsg("Invalid " <<opn <<" argument - " <<opv);
00241 else eMsg(opn <<" argument not specified.");
00242 }
00243
00244 cerr <<"\nUsage: " <<XrdpgmName <<" [options] action\n";
00245 cerr <<"\nOptions: [-d] [-g grpname] [-h hold] [-k keyname] [-l keylen] [-n keynum]";
00246 cerr <<"\n [-s {c|g|k|n|u|x}] [-u usrname] [-x {days | mm/dd/yy}]" <<endl;
00247 cerr <<"\nActions: {add | del | install | list} [keyfn]" <<endl;
00248 exit(rc);
00249 }
00250
00251
00252
00253
00254
00255 int XrdSecsssAdmin_addKey(XrdsecsssAdmin_Opts &Opt)
00256 {
00257 XrdOucErrInfo eInfo;
00258 XrdSecsssKT::ktEnt *ktEnt;
00259 int retc, numKeys, numTot, numExp;
00260
00261
00262
00263 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
00264 if ((retc = eInfo.getErrInfo()))
00265 {if (retc != ENOENT || isNo(0, "Keyfile '", Opt.KeyFile,
00266 "' does not exist. Create it? (y | n): ")) return 4;
00267 }
00268
00269
00270
00271 ktEnt = new XrdSecsssKT::ktEnt;
00272 strcpy(ktEnt->Data.Name, (Opt.KeyName ? Opt.KeyName : "nowhere"));
00273 strcpy(ktEnt->Data.User, (Opt.KeyUser ? Opt.KeyUser : "nobody"));
00274 strcpy(ktEnt->Data.Grup, (Opt.KeyGrup ? Opt.KeyGrup : "nogroup"));
00275 if (Opt.KeyLen > XrdSecsssKT::ktEnt::maxKLen)
00276 ktEnt->Data.Len = XrdSecsssKT::ktEnt::maxKLen;
00277 else if (Opt.KeyLen < 4) ktEnt->Data.Len = 4;
00278 else ktEnt->Data.Len = Opt.KeyLen/4*4;
00279 ktEnt->Data.Exp = Opt.Expdt;
00280 Opt.kTab->addKey(*ktEnt);
00281
00282
00283
00284 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
00285 {eMsg("Unable to add key to '" <<Opt.KeyFile <<"'; " <<strerror(retc));
00286 retc = 8;
00287 } else {
00288 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
00289 <<numTot <<" kept (" <<numExp <<" expired).");
00290 }
00291
00292
00293
00294 return retc;
00295 }
00296
00297
00298
00299
00300
00301 int XrdSecsssAdmin_delKey(XrdsecsssAdmin_Opts &Opt)
00302 {
00303 XrdOucErrInfo eInfo;
00304 XrdSecsssKT::ktEnt ktEnt;
00305 int retc, numKeys, numTot, numExp, numDel;
00306
00307
00308
00309 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
00310 if ((retc = eInfo.getErrInfo()))
00311 {if (retc == ENOENT)
00312 {eMsg("Keyfile '" <<Opt.KeyFile <<"' does not exist.");}
00313 return 4;
00314 }
00315
00316
00317
00318 if (Opt.KeyName) strcpy(ktEnt.Data.Name, Opt.KeyName);
00319 if (Opt.KeyUser) strcpy(ktEnt.Data.User, Opt.KeyUser);
00320 if (Opt.KeyGrup) strcpy(ktEnt.Data.Grup, Opt.KeyGrup);
00321 ktEnt.Data.ID = static_cast<long long>(Opt.KeyNum);
00322
00323
00324
00325 if (!(numDel = Opt.kTab->delKey(ktEnt)))
00326 {eMsg("No matching key(s) found.");
00327 return 4;
00328 }
00329
00330
00331
00332 if (Opt.kTab->keyList() == 0)
00333 {if (isNo(1, "No keys will remain in ", Opt.KeyFile,
00334 ". Delete file? (n | y): "))
00335 {eMsg("No keys deleted!"); return 2;}
00336 unlink(Opt.KeyFile);
00337 return 0;
00338 }
00339
00340
00341
00342 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
00343 {eMsg("Unable to del key from '" <<Opt.KeyFile <<"'; " <<strerror(retc));
00344 retc = 8;
00345 } else {
00346 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
00347 <<(numTot+numDel) <<" kept (" <<numExp <<" expired).");
00348 }
00349
00350
00351
00352 return retc;
00353 }
00354
00355
00356
00357
00358
00359 int XrdSecsssAdmin_insKey(XrdsecsssAdmin_Opts &Opt)
00360 {
00361 extern int XrdSecsssAdmin_isKey(XrdsecsssAdmin_Opts &Opt,
00362 XrdSecsssKT::ktEnt *ktP);
00363 XrdOucErrInfo eInfo;
00364 XrdSecsssKT::ktEnt *ktP;
00365 int retc, numKeys = 0, numTot, numExp;
00366
00367
00368
00369 Opt.kTab = new XrdSecsssKT(&eInfo, 0, XrdSecsssKT::isAdmin);
00370 if ((retc = eInfo.getErrInfo())) return 4;
00371
00372
00373
00374 if (Opt.KeyName || Opt.KeyUser || Opt.KeyGrup)
00375 {ktP = Opt.kTab->keyList();
00376 while(ktP)
00377 {if (!XrdSecsssAdmin_isKey(Opt, ktP)) ktP->Data.Name[0] = '\0';
00378 else numKeys++;
00379 ktP = ktP->Next;
00380 }
00381 if (!numKeys)
00382 {eMsg("No keys named " <<Opt.KeyName <<" found to install.");
00383 return 8;
00384 }
00385 }
00386
00387
00388
00389 Opt.kTab->setPath(Opt.KeyFile);
00390 if ((retc = Opt.kTab->Rewrite(Opt.Keep, numKeys, numTot, numExp)))
00391 {eMsg("Unable to install keytab '" <<Opt.KeyFile <<"'; " <<strerror(retc));
00392 retc = 8;
00393 } else {
00394 eMsg(numKeys <<(numKeys == 1 ? " key":" keys") <<" out of "
00395 <<numTot <<" installed (" <<numExp <<" expired).");
00396 }
00397
00398
00399
00400 return retc;
00401 }
00402
00403
00404
00405
00406
00407 int XrdSecsssAdmin_isKey(XrdsecsssAdmin_Opts &Opt,
00408 XrdSecsssKT::ktEnt *ktP)
00409 {
00410 if (Opt.KeyName && strcmp(ktP->Data.Name, Opt.KeyName)) return 0;
00411 if (Opt.KeyUser && strcmp(ktP->Data.User, Opt.KeyUser)) return 0;
00412 if (Opt.KeyGrup && strcmp(ktP->Data.Grup, Opt.KeyGrup)) return 0;
00413 return 1;
00414 }
00415
00416
00417
00418
00419
00420 int XrdSecsssAdmin_Here(char sType, XrdSecsssKT::ktEnt *ktX,
00421 XrdSecsssKT::ktEnt *ktS)
00422 {
00423 int n;
00424 char *sf1, *sf2;
00425
00426 switch(sType)
00427 {case 'c': return ktX->Data.Crt < ktS->Data.Crt;
00428 case 'g': sf1 = ktX->Data.Grup; sf2 = ktS->Data.Grup; break;
00429 case 'k': sf1 = ktX->Data.Name; sf2 = ktS->Data.Name; break;
00430 case 'n': return (ktX->Data.ID & 0x7fffffff) < (ktS->Data.ID & 0x7fffffff);
00431 case 'u': sf1 = ktX->Data.User; sf2 = ktS->Data.User; break;
00432 case 'x': return ktX->Data.Exp < ktS->Data.Exp;
00433 default: return 0;
00434 }
00435
00436 if ((n = strcmp(sf1, sf2))) return n < 0;
00437 return (ktX->Data.ID & 0x7fffffff) < (ktS->Data.ID & 0x7fffffff);
00438 }
00439
00440
00441
00442
00443
00444 int XrdSecsssAdmin_lstKey(XrdsecsssAdmin_Opts &Opt)
00445 {
00446 static const char Hdr1[] =
00447 " Number Len Date/Time Created Expires Keyname User & Group\n";
00448
00449 static const char Hdr2[] =
00450 " ------ --- --------- ------- -------- -------\n";
00451
00452 extern int XrdSecsssAdmin_isKey(XrdsecsssAdmin_Opts &Opt,
00453 XrdSecsssKT::ktEnt *ktP);
00454 XrdOucErrInfo eInfo;
00455 XrdSecsssKT::ktEnt *ktP, *ktSort = 0, *ktS, *ktSP, *ktX;
00456 char crfmt[] = "%D %T", exfmt[] = "%D";
00457 char buff[128], crbuff[64], exbuff[16];
00458 int retc, pHdr = 1;
00459
00460
00461
00462 Opt.kTab = new XrdSecsssKT(&eInfo, Opt.KeyFile, XrdSecsssKT::isAdmin);
00463 if ((retc = eInfo.getErrInfo()))
00464 {if (retc == ENOENT)
00465 {eMsg("Keyfile '" <<Opt.KeyFile <<"' does not exist.");}
00466 return 4;
00467 }
00468
00469
00470
00471 if ((ktP = Opt.kTab->keyList()))
00472 {ktSort = ktP; ktP = ktP->Next; ktSort->Next = 0;}
00473
00474
00475
00476 while(ktP)
00477 {ktS = ktSort; ktSP = 0; ktX = ktP; ktP = ktP->Next; ktX->Next = 0;
00478 while(ktS)
00479 {if (XrdSecsssAdmin_Here(Opt.Sort, ktX, ktS))
00480 {if (ktSP) {ktX->Next = ktS; ktSP->Next = ktX;}
00481 else {ktX->Next = ktSort; ktSort = ktX;}
00482 break;
00483 }
00484 ktSP = ktS; ktS = ktS->Next;
00485 }
00486 if (!ktS) ktSP->Next = ktX;
00487 }
00488
00489
00490
00491 ktP = ktSort;
00492 while(ktP)
00493 {if (XrdSecsssAdmin_isKey(Opt, ktP))
00494 {if (pHdr) {cout <<Hdr1 <<Hdr2; pHdr = 0;}
00495 sprintf(buff, "%11lld %3d ", (ktP->Data.ID & 0x7fffffff), ktP->Data.Len);
00496 strftime(crbuff, sizeof(crbuff), crfmt, localtime(&ktP->Data.Crt));
00497 if (!ktP->Data.Exp) strcpy(exbuff, "--------");
00498 else strftime(exbuff,sizeof(exbuff),exfmt,localtime(&ktP->Data.Exp));
00499 cout <<buff <<crbuff <<' ' <<exbuff <<' ' <<ktP->Data.Name <<' '
00500 <<ktP->Data.User <<' ' <<ktP->Data.Grup <<endl;
00501 }
00502 ktP = ktP->Next;
00503 }
00504
00505
00506
00507 if (pHdr)
00508 {if (Opt.KeyName) eMsg(Opt.KeyName <<" key not found in " <<Opt.KeyFile);
00509 else eMsg("No keys found in " <<Opt.KeyFile);
00510 }
00511 return 0;
00512 }
00513
00514