00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <unistd.h>
00012 #include <ctype.h>
00013 #include <errno.h>
00014 #include <stdlib.h>
00015 #include <strings.h>
00016 #include <stdio.h>
00017 #include <sys/param.h>
00018
00019 #include "XrdOuc/XrdOucErrInfo.hh"
00020 #include "XrdSys/XrdSysHeaders.hh"
00021 #include "XrdSys/XrdSysPthread.hh"
00022 #include "XrdOuc/XrdOucTokenizer.hh"
00023 #include "XrdSec/XrdSecInterface.hh"
00024
00025 #include "kerberosIV/krb.h"
00026 typedef int krb_rc;
00027
00028
00029
00030
00031
00032 #define XrdSecPROTOIDENT "krb4"
00033 #define XrdSecPROTOIDLEN sizeof(XrdSecPROTOIDENT)
00034 #define XrdSecNOIPCHK 0x0001
00035 #define XrdSecDEBUG 0x1000
00036
00037 #define CLDBG(x) if (options & XrdSecDEBUG) cerr <<"sec_krb4: " <<x <<endl;
00038
00039
00040
00041
00042
00043 class XrdSecProtocolkrb4 : public XrdSecProtocol
00044 {
00045 public:
00046 friend class XrdSecProtocolDummy;
00047
00048
00049 int Authenticate (XrdSecCredentials *cred,
00050 XrdSecParameters **parms,
00051 XrdOucErrInfo *einfo=0);
00052
00053 XrdSecCredentials *getCredentials(XrdSecParameters *parm=0,
00054 XrdOucErrInfo *einfo=0);
00055
00056 static char *getPrincipal() {return Principal;}
00057
00058 static int Init_Server(XrdOucErrInfo *einfo,
00059 char *KP=0, char *kfn=0);
00060
00061 static void setOpts(int opts) {options = opts;}
00062
00063 XrdSecProtocolkrb4(const char *KP,
00064 const char *hname,
00065 const struct sockaddr *ipadd)
00066 : XrdSecProtocol(XrdSecPROTOIDENT)
00067 {Service = (KP ? strdup(KP) : 0);
00068 Entity.host = strdup(hname);
00069 memcpy(&hostaddr, ipadd, sizeof(hostaddr));
00070 CName[0] = '?'; CName[1] = '\0';
00071 Entity.name = CName;
00072 }
00073
00074 void Delete();
00075
00076 private:
00077
00078 ~XrdSecProtocolkrb4() {}
00079
00080
00081 static char *Append(char *dst, const char *src);
00082 static int Fatal(XrdOucErrInfo *erp,int rc,const char *msg1,char *KP=0,int krc=0);
00083 static int get_SIR(XrdOucErrInfo *erp, const char *sh, char *sbuff, char *ibuff,
00084 char *rbuff);
00085
00086 static XrdSysMutex krbContext;
00087 static int options;
00088 static char mySname[SNAME_SZ+1];
00089 static char myIname[INST_SZ+1];
00090 static char myRname[REALM_SZ+1];
00091
00092 static char *keyfile;
00093 static char *Principal;
00094
00095 struct sockaddr hostaddr;
00096 char CName[256];
00097 char *Service;
00098 };
00099
00100
00101
00102
00103
00104 XrdSysMutex XrdSecProtocolkrb4::krbContext;
00105 int XrdSecProtocolkrb4::options = 0;
00106
00107 char XrdSecProtocolkrb4::mySname[SNAME_SZ+1];
00108 char XrdSecProtocolkrb4::myIname[INST_SZ+1];
00109 char XrdSecProtocolkrb4::myRname[REALM_SZ+1];
00110 char *XrdSecProtocolkrb4::keyfile = 0;
00111 char *XrdSecProtocolkrb4::Principal = 0;
00112
00113
00114
00115
00116
00117 void XrdSecProtocolkrb4::Delete()
00118 {
00119 if (Entity.host) free(Entity.host);
00120 if (Service) free(Service);
00121 delete this;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 XrdSecCredentials *XrdSecProtocolkrb4::getCredentials(XrdSecParameters *noparm,
00133 XrdOucErrInfo *error)
00134 {
00135 const long cksum = 0L;
00136 struct ktext katix;
00137 krb_rc rc;
00138 char *buff;
00139 char sname[SNAME_SZ+1];
00140 char iname[INST_SZ+1];
00141 char rname[REALM_SZ+1];
00142
00143
00144
00145 if (!Service)
00146 {Fatal(error, EINVAL, "krb4 service Principal name not specified.");
00147 return (XrdSecCredentials *)0;
00148 }
00149 if (get_SIR(error, Service, sname, iname, rname) < 0)
00150 return (XrdSecCredentials *)0;
00151 CLDBG("sname='" <<sname <<"' iname='" <<iname <<"' rname='" <<rname <<"'");
00152
00153
00154
00155 if (!sname[0])
00156 {CLDBG("Null credentials supplied.");
00157 return new XrdSecCredentials(0,0);
00158 }
00159
00160
00161
00162 krbContext.Lock();
00163 rc = krb_mk_req(&katix, sname, iname, rname, cksum);
00164 krbContext.UnLock();
00165
00166
00167
00168
00169
00170
00171
00172 if (rc == KSUCCESS)
00173 {int bsz = XrdSecPROTOIDLEN+katix.length;
00174 if (!(buff = (char *)malloc(bsz)))
00175 {Fatal(error,ENOMEM,"Insufficient memory for credentials.",Service);
00176 return (XrdSecCredentials *)0;
00177 }
00178 strcpy(buff, XrdSecPROTOIDENT);
00179 memcpy((void *)(buff+XrdSecPROTOIDLEN),
00180 (const void *)katix.dat, (size_t)katix.length);
00181 CLDBG("Returned " <<bsz <<" bytes of credentials; p=" <<sname);
00182 return new XrdSecCredentials(buff, bsz);
00183 }
00184
00185
00186
00187 {char ebuff[1024];
00188 snprintf(ebuff, sizeof(ebuff)-1, "Unable to get credentials from %s;",
00189 Service);
00190 ebuff[sizeof(ebuff)-1] = '\0';
00191 Fatal(error, EACCES, ebuff, Service, rc);
00192 return (XrdSecCredentials *)0;
00193 }
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203 int XrdSecProtocolkrb4::Authenticate(XrdSecCredentials *cred,
00204 XrdSecParameters **parms,
00205 XrdOucErrInfo *error)
00206 {
00207 struct ktext katix;
00208 struct auth_dat pid;
00209 krb_rc rc;
00210 char *idp;
00211 unsigned int ipaddr;
00212
00213
00214
00215
00216 if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer)
00217 {strncpy(Entity.prot, "host", sizeof(Entity.prot));
00218 Entity.name[0] = '?'; Entity.name[1] = '\0';
00219 return 0;
00220 }
00221
00222
00223
00224 if (strcmp(cred->buffer, XrdSecPROTOIDENT))
00225 {char emsg[256];
00226 snprintf(emsg, sizeof(emsg),
00227 "Authentication protocol id mismatch (%.4s != %.4s).",
00228 XrdSecPROTOIDENT, cred->buffer);
00229 Fatal(error, EINVAL, emsg);
00230 return -1;
00231 }
00232
00233
00234
00235 strncpy(Entity.prot, XrdSecPROTOIDENT, sizeof(Entity.prot));
00236
00237
00238
00239 katix.length = cred->size-XrdSecPROTOIDLEN;
00240 memcpy((void *)katix.dat, (const void *)&cred->buffer[XrdSecPROTOIDLEN],
00241 (size_t) katix.length);
00242
00243
00244
00245
00246
00247 if (options & XrdSecNOIPCHK) ipaddr = 0;
00248 else {sockaddr_in *ip = (sockaddr_in *)&hostaddr;
00249 memcpy((void *)&ipaddr,(void *)&ip->sin_addr.s_addr,sizeof(ipaddr));
00250 }
00251
00252
00253
00254 krbContext.Lock();
00255 rc = krb_rd_req(&katix, mySname, myIname, ipaddr, &pid, keyfile);
00256 krbContext.UnLock();
00257
00258
00259
00260 if (rc != KSUCCESS)
00261 {Fatal(error,rc,"Unable to authenticate credentials;",Principal,rc);
00262 return -1;
00263 }
00264
00265
00266
00267 idp = Append(CName, pid.pname);
00268 if (pid.pinst[0])
00269 {*idp = '.'; idp++; idp = Append(idp, pid.pinst);}
00270 if (pid.prealm[0] && strcasecmp(pid.prealm, myRname))
00271 {*idp = '@'; idp++; idp = Append(idp, pid.prealm);}
00272
00273
00274
00275 return 0;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285 int XrdSecProtocolkrb4::Init_Server(XrdOucErrInfo *erp, char *KP, char *kfn)
00286 {
00287 int plen;
00288
00289
00290
00291 if (!KP)
00292 return Fatal(erp, EINVAL, "krb4 service Principal name not specified.");
00293 if (get_SIR(erp, KP, mySname, myIname, myRname) < 0) return -1;
00294 CLDBG("sname='" <<mySname <<"' iname='" <<myIname <<"' rname='" <<myRname <<"'");
00295
00296
00297
00298 plen = strlen(mySname) + strlen(myIname) + strlen(myRname) + 3;
00299 if (!(Principal = (char *)malloc(plen)))
00300 {Principal = (char *)"?";
00301 return Fatal(erp, ENOMEM, "insufficient storage", KP);
00302 }
00303 if (*myIname) sprintf((char *)Principal, "%s.%s@%s",mySname,myIname,myRname);
00304 else sprintf((char *)Principal, "%s@%s", mySname,myRname);
00305
00306
00307
00308 if (kfn && *kfn) keyfile = strdup(kfn);
00309 else keyfile = (char *)"";
00310
00311
00312
00313 return 0;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323 char *XrdSecProtocolkrb4::Append(char *dst, const char *src)
00324 {
00325 while(*src) {*dst = *src; dst++; src++;}
00326 *dst = '\0';
00327 return dst;
00328 }
00329
00330
00331
00332
00333
00334 int XrdSecProtocolkrb4::Fatal(XrdOucErrInfo *erp, int rc, const char *msg,
00335 char *KP, int krc)
00336 {
00337 const char *msgv[8];
00338 int k, i = 0;
00339
00340 msgv[i++] = "Seckrb4: ";
00341 msgv[i++] = msg;
00342 if (krc) {msgv[i++] = "; ";
00343 msgv[i++] = krb_err_txt[rc];
00344 }
00345 if (KP) {msgv[i++] = " (p=";
00346 msgv[i++] = KP;
00347 msgv[i++] = ").";
00348 }
00349 if (erp) erp->setErrInfo(rc, msgv, i);
00350 else {for (k = 0; k < i; k++) cerr <<msgv[k];
00351 cerr <<endl;
00352 }
00353
00354 return -1;
00355 }
00356
00357
00358
00359
00360
00361 int XrdSecProtocolkrb4::get_SIR(XrdOucErrInfo *erp, const char *sh,
00362 char *sbuff, char *ibuff, char *rbuff)
00363 {
00364 int h, i, j, k;
00365
00366 k = strlen(sh);
00367 if (k > MAX_K_NAME_SZ)
00368 return Fatal(erp, EINVAL, "service name is to long", (char *)sh);
00369
00370 for (j = 0; j < k && sh[j] != '@'; j++) {};
00371 if (j > k) j = k;
00372 else {if (j == k-1)
00373 return Fatal(erp,EINVAL,"realm name missing after '@'",(char *)sh);
00374 if (k-j > REALM_SZ)
00375 return Fatal(erp, EINVAL, "realm name is to long",(char *)sh);
00376 }
00377
00378 for (i = 0; i < j && sh[i] != '.'; i++) {};
00379 if (i < j) {if (j-i >= INST_SZ)
00380 return Fatal(erp, EINVAL, "instance is too long",(char *)sh);
00381 if (i+1 == j)
00382 return Fatal(erp,EINVAL,"instance name missing after '.'",(char *)sh);
00383 }
00384
00385 if (i == SNAME_SZ)
00386 return Fatal(erp, EINVAL, "service name is too long", (char *)sh);
00387 if (!i) return Fatal(erp, EINVAL, "service name not specified.");
00388
00389 strncpy(sbuff, sh, i); sbuff[i] = '\0';
00390 if ( (h = j - i - 1) <= 0) ibuff[0] = '\0';
00391 else {strncpy(ibuff, &sh[i+1], h); ibuff[h] = '\0';}
00392 if ( (h = k - j - 1) <= 0) krb_get_lrealm(rbuff, 1);
00393 else {strncpy(rbuff, &sh[j+1], h); rbuff[h] = '\0';}
00394
00395 return 1;
00396 }
00397
00398
00399
00400
00401
00402 extern "C"
00403 {
00404 char *XrdSecProtocolkrb4Init(const char mode,
00405 const char *parms,
00406 XrdOucErrInfo *erp)
00407 {
00408 char *op, *KPrincipal=0, *Keytab=0;
00409 char parmbuff[1024];
00410 XrdOucTokenizer inParms(parmbuff);
00411 int options = XrdSecNOIPCHK;
00412
00413
00414
00415
00416 if (mode == 'c')
00417 {if (getenv("XrdSecDEBUG")) XrdSecProtocolkrb4::setOpts(XrdSecDEBUG);
00418 return (char *)"";
00419 }
00420
00421
00422
00423 if (parms) strlcpy(parmbuff, parms, sizeof(parmbuff));
00424 else {char *msg = (char *)"Seckrb4: Kerberos parameters not specified.";
00425 if (erp) erp->setErrInfo(EINVAL, msg);
00426 else cerr <<msg <<endl;
00427 return (char *)0;
00428 }
00429
00430
00431
00432 if (inParms.GetLine())
00433 {if ((op = inParms.GetToken()) && *op == '/')
00434 {Keytab = op; op = inParms.GetToken();}
00435 if (op && !strcmp(op, "-ipchk"))
00436 {options &= ~XrdSecNOIPCHK;
00437 op = inParms.GetToken();
00438 }
00439 KPrincipal = op;
00440 }
00441
00442
00443
00444 if (!KPrincipal)
00445 {char *msg = (char *)"Seckrb4: Kerberos principal not specified.";
00446 if (erp) erp->setErrInfo(EINVAL, msg);
00447 else cerr <<msg <<endl;
00448 return (char *)0;
00449 }
00450
00451
00452
00453 XrdSecProtocolkrb4::setOpts(options);
00454 return (XrdSecProtocolkrb4::Init_Server(erp, KPrincipal, Keytab)
00455 ? (char *)0 : XrdSecProtocolkrb4::getPrincipal());
00456 }
00457 }
00458
00459
00460
00461
00462
00463 extern "C"
00464 {
00465 XrdSecProtocol *XrdSecProtocolkrb4Object(const char mode,
00466 const char *hostname,
00467 const struct sockaddr &netaddr,
00468 const char *parms,
00469 XrdOucErrInfo *erp)
00470 {
00471 XrdSecProtocolkrb4 *prot;
00472 char *KPrincipal=0;
00473
00474
00475
00476
00477
00478 if (mode == 'c')
00479 {if ((KPrincipal = (char *)parms)) while(*KPrincipal == ' ') KPrincipal++;
00480 if (!KPrincipal || !*KPrincipal)
00481 {char *msg = (char *)"Seckrb4: Kerberos principal not specified.";
00482 if (erp) erp->setErrInfo(EINVAL, msg);
00483 else cerr <<msg <<endl;
00484 return (XrdSecProtocol *)0;
00485 }
00486 }
00487
00488
00489
00490 if (!(prot = new XrdSecProtocolkrb4(KPrincipal, hostname, &netaddr)))
00491 {char *msg = (char *)"Seckrb4: Insufficient memory for protocol.";
00492 if (erp) erp->setErrInfo(ENOMEM, msg);
00493 else cerr <<msg <<endl;
00494 return (XrdSecProtocol *)0;
00495 }
00496
00497
00498
00499 return prot;
00500 }
00501 }