00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <unistd.h>
00015 #include <ctype.h>
00016 #include <errno.h>
00017 #include <stdlib.h>
00018 #include <strings.h>
00019 #include <stdio.h>
00020 #include <sys/param.h>
00021 #include <pwd.h>
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024
00025
00026 extern "C" {
00027 #include "krb5.h"
00028 #ifdef HAVE_ET_COM_ERR_H
00029 #include "et/com_err.h"
00030 #else
00031 #include "com_err.h"
00032 #endif
00033 }
00034
00035 #include "XrdNet/XrdNetDNS.hh"
00036 #include "XrdOuc/XrdOucErrInfo.hh"
00037 #include "XrdSys/XrdSysHeaders.hh"
00038 #include "XrdSys/XrdSysPthread.hh"
00039 #include "XrdOuc/XrdOucTokenizer.hh"
00040 #include "XrdSec/XrdSecInterface.hh"
00041 #include "XrdSys/XrdSysPriv.hh"
00042
00043
00044
00045
00046
00047 #define krb_etxt(x) (char *)error_message(x)
00048
00049 #define XrdSecPROTOIDENT "krb5"
00050 #define XrdSecPROTOIDLEN sizeof(XrdSecPROTOIDENT)
00051 #define XrdSecNOIPCHK 0x0001
00052 #define XrdSecEXPTKN 0x0002
00053 #define XrdSecINITTKN 0x0004
00054 #define XrdSecDEBUG 0x1000
00055
00056 #define XrdSecMAXPATHLEN 4096
00057
00058 #define CLDBG(x) if (client_options & XrdSecDEBUG) cerr <<"Seckrb5: " <<x <<endl;
00059 #define CLPRT(x) cerr <<"Seckrb5: " <<x <<endl;
00060
00061 typedef krb5_error_code krb_rc;
00062
00063
00064
00065
00066
00067 class XrdSecProtocolkrb5 : public XrdSecProtocol
00068 {
00069 public:
00070 friend class XrdSecProtocolDummy;
00071
00072 int Authenticate (XrdSecCredentials *cred,
00073 XrdSecParameters **parms,
00074 XrdOucErrInfo *einfo=0);
00075
00076 XrdSecCredentials *getCredentials(XrdSecParameters *parm=0,
00077 XrdOucErrInfo *einfo=0);
00078
00079 static char *getPrincipal() {return Principal;}
00080
00081 static int Init(XrdOucErrInfo *einfo, char *KP=0, char *kfn=0);
00082
00083 static void setOpts(int opts) {options = opts;}
00084 static void setClientOpts(int opts) {client_options = opts;}
00085 static void setParms(char *param) {Parms = param;}
00086 static void setExpFile(char *expfile)
00087 {if (expfile)
00088 {int lt = strlen(expfile);
00089 lt = (lt >= XrdSecMAXPATHLEN) ?
00090 XrdSecMAXPATHLEN -1 : lt;
00091 memcpy(ExpFile, expfile, lt);
00092 ExpFile[lt] = 0;
00093 }
00094 }
00095
00096 XrdSecProtocolkrb5(const char *KP,
00097 const char *hname,
00098 const struct sockaddr *ipadd)
00099 : XrdSecProtocol(XrdSecPROTOIDENT)
00100 {Service = (KP ? strdup(KP) : 0);
00101 Entity.host = strdup(hname);
00102 memcpy(&hostaddr, ipadd, sizeof(hostaddr));
00103 CName[0] = '?'; CName[1] = '\0';
00104 Entity.name = CName;
00105 Step = 0;
00106 AuthContext = 0;
00107 AuthClientContext = 0;
00108 Ticket = 0;
00109 Creds = 0;
00110 }
00111
00112 void Delete();
00113
00114 private:
00115
00116 ~XrdSecProtocolkrb5() {}
00117
00118 static int Fatal(XrdOucErrInfo *erp,int rc,const char *msg1,char *KP=0,int krc=0);
00119 static int get_krbCreds(char *KP, krb5_creds **krb_creds);
00120
00121 static XrdSysMutex krbContext;
00122 static XrdSysMutex krbClientContext;
00123 static int options;
00124 static int client_options;
00125 static krb5_context krb_context;
00126 static krb5_context krb_client_context;
00127 static krb5_ccache krb_client_ccache;
00128 static krb5_ccache krb_ccache;
00129 static krb5_keytab krb_keytab;
00130 static uid_t krb_kt_uid;
00131 static gid_t krb_kt_gid;
00132 static krb5_principal krb_principal;
00133
00134 static char *Principal;
00135 static char *Parms;
00136
00137 static char ExpFile[XrdSecMAXPATHLEN];
00138
00139 int exp_krbTkn(XrdSecCredentials *cred, XrdOucErrInfo *erp);
00140 int get_krbFwdCreds(char *KP, krb5_data *outdata);
00141
00142 struct sockaddr hostaddr;
00143 char CName[256];
00144 char *Service;
00145 char Step;
00146 krb5_auth_context AuthContext;
00147 krb5_auth_context AuthClientContext;
00148 krb5_ticket *Ticket;
00149 krb5_creds *Creds;
00150 };
00151
00152
00153
00154
00155
00156 XrdSysMutex XrdSecProtocolkrb5::krbContext;
00157 XrdSysMutex XrdSecProtocolkrb5::krbClientContext;
00158
00159 int XrdSecProtocolkrb5::client_options = 0;
00160 int XrdSecProtocolkrb5::options = 0;
00161 krb5_context XrdSecProtocolkrb5::krb_context;
00162 krb5_context XrdSecProtocolkrb5::krb_client_context;
00163 krb5_ccache XrdSecProtocolkrb5::krb_client_ccache;
00164 krb5_ccache XrdSecProtocolkrb5::krb_ccache;
00165 krb5_keytab XrdSecProtocolkrb5::krb_keytab = NULL;
00166 uid_t XrdSecProtocolkrb5::krb_kt_uid = 0;
00167 gid_t XrdSecProtocolkrb5::krb_kt_gid = 0;
00168 krb5_principal XrdSecProtocolkrb5::krb_principal;
00169
00170 char *XrdSecProtocolkrb5::Principal = 0;
00171 char *XrdSecProtocolkrb5::Parms = 0;
00172
00173 char XrdSecProtocolkrb5::ExpFile[XrdSecMAXPATHLEN] = "/tmp/krb5cc_<uid>";
00174
00175
00176
00177
00178
00179 void XrdSecProtocolkrb5::Delete()
00180 {
00181 if (Parms) free(Parms); Parms = 0;
00182 if (Creds) krb5_free_creds(krb_context, Creds);
00183 if (Ticket) krb5_free_ticket(krb_context, Ticket);
00184 if (AuthContext) krb5_auth_con_free(krb_context, AuthContext);
00185 if (AuthClientContext) krb5_auth_con_free(krb_client_context, AuthClientContext);
00186 if (Entity.host) free(Entity.host);
00187 if (Service) free(Service);
00188 delete this;
00189 }
00190
00191
00192
00193
00194
00195 XrdSecCredentials *XrdSecProtocolkrb5::getCredentials(XrdSecParameters *noparm,
00196 XrdOucErrInfo *error)
00197 {
00198 char *buff;
00199 int bsz;
00200 krb_rc rc;
00201 krb5_data outbuf;
00202 CLDBG("getCredentials");
00203
00204
00205 if (!Service)
00206 {CLDBG("Null credentials supplied.");
00207 return new XrdSecCredentials(0,0);
00208 }
00209
00210
00211
00212 if (!getenv("KRB5CCNAME")) {
00213 char ccname[128];
00214 sprintf(ccname, "KRB5CCNAME=FILE:/tmp/krb5cc_%d", geteuid());
00215 putenv(strdup(ccname));
00216 }
00217 CLDBG(getenv("KRB5CCNAME"));
00218
00219
00220
00221 if ((rc = krb5_init_context(&krb_client_context)))
00222 {Fatal(error, ENOPROTOOPT, "Kerberos initialization failed", Service, rc);
00223 return (XrdSecCredentials *)0;
00224 }
00225
00226 CLDBG("init context");
00227
00228
00229 if ((rc = krb5_cc_default(krb_client_context, &krb_client_ccache)))
00230 {Fatal(error, ENOPROTOOPT, "Unable to locate cred cache", Service, rc);
00231 return (XrdSecCredentials *)0;
00232 }
00233
00234 CLDBG("cc cache default");
00235
00236
00237 char *pfwd = 0;
00238 if ((pfwd = (char *) strstr(Service,",fwd")))
00239 {
00240 client_options |= XrdSecEXPTKN;
00241 *pfwd = 0;
00242 }
00243
00244
00245
00246 outbuf.length = 0; outbuf.data = 0;
00247
00248 CLDBG("context lock");
00249 krbClientContext.Lock();
00250 CLDBG("context locked");
00251
00252
00253
00254
00255
00256
00257 if (Step > 0)
00258 {if ((rc = get_krbFwdCreds(Service, &outbuf)))
00259 {krbClientContext.UnLock();
00260 Fatal(error, ESRCH, "Unable to get forwarded credentials", Service, rc);
00261 return (XrdSecCredentials *)0;
00262 } else
00263 {bsz = XrdSecPROTOIDLEN+outbuf.length;
00264 if (!(buff = (char *)malloc(bsz)))
00265 {krbClientContext.UnLock();
00266 Fatal(error, ENOMEM, "Insufficient memory for credentials.", Service);
00267 return (XrdSecCredentials *)0;
00268 }
00269 strcpy(buff, XrdSecPROTOIDENT);
00270 memcpy((void *)(buff+XrdSecPROTOIDLEN),
00271 (const void *)outbuf.data, (size_t)outbuf.length);
00272 CLDBG("Returned " <<bsz <<" bytes of creds; p=" <<Service);
00273 if (outbuf.data) free(outbuf.data);
00274 krbClientContext.UnLock();
00275 return new XrdSecCredentials(buff, bsz);
00276 }
00277 }
00278
00279
00280
00281 Step += 1;
00282
00283
00284
00285 const char *reinitcmd = (client_options & XrdSecEXPTKN) ? "kinit -f" : "kinit";
00286 bool notdone = 1;
00287 bool reinitdone = 0;
00288 while (notdone)
00289 {if ((rc = (krb_rc)get_krbCreds(Service, &Creds)))
00290 { if (!(client_options & XrdSecINITTKN) || reinitdone)
00291 {krbClientContext.UnLock();
00292 const char *m = (!(client_options & XrdSecINITTKN)) ?
00293 "No or invalid credentials" : "Unable to get credentials";
00294 Fatal(error, ESRCH, m, Service, rc);
00295 return (XrdSecCredentials *)0;
00296 } else {
00297 CLPRT("Ticket missing or invalid: re-init ");
00298 rc = system(reinitcmd);
00299 CLDBG("getCredentials: return code from '"<<reinitcmd<<
00300 "': "<< rc);
00301 reinitdone = 1;
00302 continue;
00303 }
00304 }
00305 if (client_options & XrdSecEXPTKN)
00306 {
00307 if (!(Creds->ticket_flags & TKT_FLG_FORWARDABLE))
00308 { if ((client_options & XrdSecINITTKN) && !reinitdone)
00309 {
00310 CLPRT("Existing ticket is not forwardable: re-init ");
00311 rc = system(reinitcmd);
00312 CLDBG("getCredentials: return code from '"<<reinitcmd<<
00313 "': "<< rc);
00314 reinitdone = 1;
00315 continue;
00316 } else {
00317 krbClientContext.UnLock();
00318 Fatal(error, ESRCH, "Existing ticket is not forwardable: cannot continue",
00319 Service, rc);
00320 return (XrdSecCredentials *)0;
00321 }
00322 }
00323 }
00324
00325 notdone = 0;
00326 }
00327
00328
00329
00330 if ((rc = krb5_auth_con_init(krb_client_context, &AuthClientContext)))
00331 {krbClientContext.UnLock();
00332 Fatal(error, ESRCH, "Unable to init a new auth context", Service, rc);
00333 return (XrdSecCredentials *)0;
00334 }
00335
00336
00337
00338 rc = krb5_mk_req_extended(krb_client_context, &AuthClientContext,
00339 AP_OPTS_USE_SESSION_KEY,(krb5_data *)0, Creds,&outbuf);
00340
00341
00342
00343
00344
00345 if (!rc)
00346 {bsz = XrdSecPROTOIDLEN+outbuf.length;
00347 if (!(buff = (char *)malloc(bsz)))
00348 {krbClientContext.UnLock();
00349 Fatal(error, ENOMEM, "Insufficient memory for credentials.", Service);
00350 return (XrdSecCredentials *)0;
00351 }
00352 strcpy(buff, XrdSecPROTOIDENT);
00353 memcpy((void *)(buff+XrdSecPROTOIDLEN),
00354 (const void *)outbuf.data, (size_t)outbuf.length);
00355 CLDBG("Returned " <<bsz <<" bytes of creds; p=" <<Service);
00356 if (outbuf.data) free(outbuf.data);
00357 krbClientContext.UnLock();
00358 return new XrdSecCredentials(buff, bsz);
00359 }
00360
00361
00362
00363 if (outbuf.data) free(outbuf.data);
00364 krbClientContext.UnLock();
00365 Fatal(error, EACCES, "Unable to get credentials", Service, rc);
00366 return (XrdSecCredentials *)0;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376 int XrdSecProtocolkrb5::Authenticate(XrdSecCredentials *cred,
00377 XrdSecParameters **parms,
00378 XrdOucErrInfo *error)
00379 {
00380 krb5_data inbuf;
00381 krb5_address ipadd;
00382 krb_rc rc = 0;
00383 char *iferror = 0;
00384
00385
00386
00387
00388 if (cred->size <= (int)XrdSecPROTOIDLEN || !cred->buffer)
00389 {strncpy(Entity.prot, "host", sizeof(Entity.prot));
00390 return 0;
00391 }
00392
00393
00394
00395 if (strcmp(cred->buffer, XrdSecPROTOIDENT))
00396 {char emsg[256];
00397 snprintf(emsg, sizeof(emsg),
00398 "Authentication protocol id mismatch (%.4s != %.4s).",
00399 XrdSecPROTOIDENT, cred->buffer);
00400 Fatal(error, EINVAL, emsg, Principal);
00401 return -1;
00402 }
00403
00404 CLDBG("protocol check");
00405
00406 char printit[4096];
00407 sprintf(printit,"Step is %d",Step);
00408 CLDBG(printit);
00409
00410
00411
00412 if (Step > 0)
00413 {if ((rc = exp_krbTkn(cred, error)))
00414 iferror = (char *)"Unable to export the token to file";
00415 if (rc && iferror) {
00416 krbContext.UnLock();
00417 return Fatal(error, EINVAL, iferror, Principal, rc);
00418 }
00419 krbContext.UnLock();
00420
00421 return 0;
00422 }
00423
00424 CLDBG("protocol check");
00425
00426
00427
00428 Step += 1;
00429
00430
00431
00432 strncpy(Entity.prot, XrdSecPROTOIDENT, sizeof(Entity.prot));
00433
00434
00435
00436
00437 CLDBG("Context Lock");
00438
00439 inbuf.length = cred->size -XrdSecPROTOIDLEN;
00440 inbuf.data = &cred->buffer[XrdSecPROTOIDLEN];
00441
00442 krbContext.Lock();
00443
00444
00445
00446
00447 CLDBG("Context Locked");
00448 if (!(XrdSecProtocolkrb5::options & XrdSecNOIPCHK))
00449 {struct sockaddr_in *ip = (struct sockaddr_in *)&hostaddr;
00450
00451 ipadd.addrtype = ADDRTYPE_INET;
00452 ipadd.length = sizeof(ip->sin_addr);
00453 ipadd.contents = (krb5_octet *)&ip->sin_addr;
00454 iferror = (char *)"Unable to validate ip address;";
00455 if (!(rc=krb5_auth_con_init(krb_context, &AuthContext)))
00456 rc=krb5_auth_con_setaddrs(krb_context, AuthContext, NULL, &ipadd);
00457 }
00458
00459
00460
00461 { XrdSysPrivGuard pGuard(krb_kt_uid, krb_kt_gid);
00462 if (pGuard.Valid())
00463 {if (!rc)
00464 {if ((rc = krb5_rd_req(krb_context, &AuthContext, &inbuf,
00465 (krb5_const_principal)krb_principal,
00466 krb_keytab, NULL, &Ticket)))
00467 iferror = (char *)"Unable to authenticate credentials;";
00468 else if ((rc = krb5_aname_to_localname(krb_context,
00469 Ticket->enc_part2->client,
00470 sizeof(CName)-1, CName)))
00471 iferror = (char *)"Unable to extract client name;";
00472 }
00473 } else
00474 iferror = (char *)"Unable to acquire privileges to read the keytab;";
00475 }
00476
00477
00478 CName[sizeof(CName)-1] = '\0';
00479
00480
00481 int hsrc = 0;
00482 if (!rc && XrdSecProtocolkrb5::options & XrdSecEXPTKN) {
00483
00484 hsrc = 1;
00485
00486 int len = strlen("fwdtgt") + 1;
00487 char *buf = (char *) malloc(len);
00488 memcpy(buf, "fwdtgt", len-1);
00489 buf[len-1] = 0;
00490 *parms = new XrdSecParameters(buf, len);
00491 }
00492
00493
00494
00495 krbContext.UnLock();
00496
00497
00498
00499 if (rc && iferror)
00500 return Fatal(error, EACCES, iferror, Principal, rc);
00501
00502
00503
00504 return hsrc;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514 int XrdSecProtocolkrb5::Init(XrdOucErrInfo *erp, char *KP, char *kfn)
00515 {
00516 krb_rc rc;
00517 char buff[1024];
00518
00519
00520
00521
00522
00523
00524 if (!KP) {
00525 if ((rc = krb5_init_context(&krb_client_context)))
00526 return Fatal(erp, ENOPROTOOPT, "Kerberos initialization failed", KP, rc);
00527
00528
00529
00530 if ((rc = krb5_cc_default(krb_client_context, &krb_client_ccache)))
00531 return Fatal(erp, ENOPROTOOPT, "Unable to locate cred cache", KP, rc);
00532
00533 return 0;
00534 }
00535
00536 if ((rc = krb5_init_context(&krb_context)))
00537 return Fatal(erp, ENOPROTOOPT, "Kerberos initialization failed", KP, rc);
00538
00539
00540
00541 if ((rc = krb5_cc_default(krb_context, &krb_ccache)))
00542 return Fatal(erp, ENOPROTOOPT, "Unable to locate cred cache", KP, rc);
00543
00544
00545
00546 if (kfn && *kfn)
00547 {if ((rc = krb5_kt_resolve(krb_context, kfn, &krb_keytab)))
00548 {snprintf(buff, sizeof(buff), "Unable to find keytab '%s';", kfn);
00549 return Fatal(erp, ESRCH, buff, Principal, rc);
00550 }
00551 } else {
00552 krb5_kt_default(krb_context, &krb_keytab);
00553 }
00554
00555
00556
00557 char krb_kt_name[1024];
00558 if ((rc = krb5_kt_get_name(krb_context, krb_keytab, &krb_kt_name[0], 1024)))
00559 {snprintf(buff, sizeof(buff), "Unable to get keytab name;");
00560 return Fatal(erp, ESRCH, buff, Principal, rc);
00561 }
00562
00563
00564
00565
00566 krb_kt_uid = 0;
00567 krb_kt_gid = 0;
00568 char *pf = 0;
00569 if ((pf = (char *) strstr(krb_kt_name, "FILE:")))
00570 {pf += strlen("FILE:");
00571 if (strlen(pf) > 0)
00572 {struct stat st;
00573 if (!stat(pf, &st))
00574 {if (st.st_uid != geteuid() || st.st_gid != getegid())
00575 {krb_kt_uid = st.st_uid;
00576 krb_kt_gid = st.st_gid;
00577 }
00578 }
00579 }
00580 }
00581
00582
00583
00584 if ((rc = krb5_parse_name(krb_context,KP,&krb_principal)))
00585 return Fatal(erp, EINVAL, "Cannot parse service name", KP, rc);
00586
00587
00588
00589 if ((rc = krb5_unparse_name(krb_context,(krb5_const_principal)krb_principal,
00590 (char **)&Principal)))
00591 return Fatal(erp, EINVAL, "Unable to unparse principal;", KP, rc);
00592
00593
00594
00595 return 0;
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605 int XrdSecProtocolkrb5::Fatal(XrdOucErrInfo *erp, int rc, const char *msg,
00606 char *KP, int krc)
00607 {
00608 const char *msgv[8];
00609 int k, i = 0;
00610
00611 msgv[i++] = "Seckrb5: ";
00612 msgv[i++] = msg;
00613 if (krc) {msgv[i++] = "; ";
00614 msgv[i++] = krb_etxt(krc);
00615 }
00616 if (KP) {msgv[i++] = " (p=";
00617 msgv[i++] = KP;
00618 msgv[i++] = ").";
00619 }
00620 if (erp) erp->setErrInfo(rc, msgv, i);
00621 else {for (k = 0; k < i; k++) cerr <<msgv[k];
00622 cerr <<endl;
00623 }
00624
00625 return -1;
00626 }
00627
00628
00629
00630
00631
00632
00633
00634 int XrdSecProtocolkrb5::get_krbCreds(char *KP, krb5_creds **krb_creds)
00635 {
00636 krb_rc rc;
00637 krb5_principal the_principal;
00638 krb5_creds mycreds;
00639
00640
00641
00642 memset((char *)&mycreds, 0, sizeof(mycreds));
00643
00644
00645
00646 if ((rc = krb5_parse_name(krb_client_context,KP,&the_principal)))
00647 {CLDBG("get_krbCreds: Cannot parse service name;" <<krb_etxt(rc));
00648 return rc;
00649 }
00650
00651
00652
00653 if ((rc = krb5_copy_principal(krb_client_context, the_principal, &mycreds.server)))
00654 {CLDBG("get_krbCreds: err copying principal to creds; " <<krb_etxt(rc));
00655 return rc;
00656 }
00657
00658
00659
00660 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &mycreds.client)))
00661 {krb5_free_cred_contents(krb_client_context, &mycreds);
00662 CLDBG("get_krbCreds: err copying client name to creds; " <<krb_etxt(rc));
00663 return rc;
00664 }
00665
00666
00667
00668 rc = krb5_get_credentials(krb_client_context, 0, krb_client_ccache, &mycreds, krb_creds);
00669 krb5_free_cred_contents(krb_client_context, &mycreds);
00670
00671
00672
00673 if (rc) {CLDBG("get_krbCreds: unable to get creds; " <<krb_etxt(rc));}
00674 return rc;
00675 }
00676
00677
00678
00679
00680
00681 int XrdSecProtocolkrb5::get_krbFwdCreds(char *KP, krb5_data *outdata)
00682 {
00683 int rc;
00684 krb5_principal client, server;
00685
00686
00687
00688 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &client)))
00689 {CLDBG("get_krbFwdCreds: err filling client principal; " <<krb_etxt(rc));
00690 return rc;
00691 }
00692
00693
00694
00695 if ((rc = krb5_parse_name(krb_client_context, KP, &server)))
00696 {CLDBG("get_krbFwdCreds: Cannot parse service principal;" <<krb_etxt(rc));
00697 return rc;
00698 }
00699
00700
00701
00702 if ((rc = krb5_auth_con_setflags(krb_client_context, AuthClientContext,
00703 KRB5_AUTH_CONTEXT_RET_TIME)))
00704 {CLDBG("Unable to set KRB5_AUTH_CONTEXT_RET_TIME"
00705 " in the authentication context" << krb_etxt(rc));
00706 return rc;
00707 }
00708
00709
00710
00711 if ((rc = krb5_fwd_tgt_creds(krb_client_context, AuthClientContext, 0 ,
00712 client, server, krb_client_ccache, true,
00713 outdata)))
00714 {CLDBG("get_krbFwdCreds: err getting forwarded ticket;" <<krb_etxt(rc));
00715 return rc;
00716 }
00717
00718
00719
00720 return rc;
00721 }
00722
00723
00724
00725
00726
00727 int XrdSecProtocolkrb5::exp_krbTkn(XrdSecCredentials *cred, XrdOucErrInfo *erp)
00728 {
00729 int rc = 0;
00730
00731
00732
00733 char ccfile[XrdSecMAXPATHLEN];
00734 strcpy(ccfile, XrdSecProtocolkrb5::ExpFile);
00735 int nlen = strlen(ccfile);
00736 char *pusr = (char *) strstr(&ccfile[0], "<user>");
00737 if (pusr)
00738 {int ln = strlen(CName);
00739 if (ln != 6) {
00740
00741 int lm = strlen(ccfile) - (int)(pusr + 6 - &ccfile[0]);
00742 memmove(pusr+ln, pusr+6, lm);
00743 }
00744
00745 memcpy(pusr, CName, ln);
00746
00747 nlen += (ln - 6);
00748 }
00749 char *puid = (char *) strstr(&ccfile[0], "<uid>");
00750 struct passwd *pw = getpwnam(CName);
00751 if (puid)
00752 {char cuid[20] = {0};
00753 if (pw)
00754 sprintf(cuid, "%d", pw->pw_uid);
00755 int ln = strlen(cuid);
00756 if (ln != 5) {
00757
00758 int lm = strlen(ccfile) - (int)(puid + 5 - &ccfile[0]);
00759 memmove(puid+ln, pusr+5, lm);
00760 }
00761
00762 memcpy(puid, cuid, ln);
00763
00764 nlen += (ln - 5);
00765 }
00766
00767
00768
00769 ccfile[nlen] = 0;
00770
00771
00772
00773 krbContext.Lock();
00774 krb5_data forwardCreds;
00775 forwardCreds.data = &cred->buffer[XrdSecPROTOIDLEN];
00776 forwardCreds.length = cred->size -XrdSecPROTOIDLEN;
00777
00778
00779
00780 krb5_rcache rcache;
00781 if ((rc = krb5_get_server_rcache(krb_context,
00782 krb5_princ_component(krb_context, krb_principal, 0),
00783 &rcache)))
00784 return rc;
00785 if ((rc = krb5_auth_con_setrcache(krb_context, AuthContext, rcache)))
00786 return rc;
00787
00788
00789
00790 if ((rc = krb5_auth_con_setaddrs(krb_context, AuthContext, 0, (krb5_address *)&hostaddr)))
00791 return rc;
00792
00793
00794
00795 krb5_creds **creds = 0;
00796 if ((rc = krb5_rd_cred(krb_context, AuthContext,
00797 &forwardCreds, &creds, 0)))
00798 return rc;
00799
00800
00801 krb5_ccache cache = 0;
00802 if ((rc = krb5_cc_resolve(krb_context, ccfile, &cache)))
00803 return rc;
00804
00805
00806
00807 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00808 if (!pGuard.Valid())
00809 return Fatal(erp, EINVAL, "Unable to acquire privileges;", ccfile, 0);
00810
00811
00812
00813 if ((rc = krb5_cc_initialize(krb_context, cache,
00814 Ticket->enc_part2->client)))
00815 return rc;
00816
00817
00818
00819 if ((rc = krb5_cc_store_cred(krb_context, cache, *creds)))
00820 return rc;
00821
00822
00823 if ((rc = krb5_cc_close(krb_context, cache)))
00824 return rc;
00825
00826
00827
00828 if (chown(ccfile, pw->pw_uid, pw->pw_gid) == -1)
00829 return Fatal(erp, errno, "Unable to change file ownership;", ccfile, 0);
00830 if (chmod(ccfile, 0600) == -1)
00831 return Fatal(erp, errno, "Unable to change file permissions;", ccfile, 0);
00832
00833
00834
00835 return 0;
00836 }
00837
00838
00839
00840
00841
00842 extern "C"
00843 {
00844 char *XrdSecProtocolkrb5Init(const char mode,
00845 const char *parms,
00846 XrdOucErrInfo *erp)
00847 {
00848 char *op, *KPrincipal=0, *Keytab=0, *ExpFile=0;
00849 char parmbuff[1024];
00850 XrdOucTokenizer inParms(parmbuff);
00851 int options = XrdSecNOIPCHK;
00852 static bool serverinitialized = false;
00853
00854
00855
00856
00857 if ((mode == 'c') || (serverinitialized))
00858 {
00859 int opts = 0;
00860 if (getenv("XrdSecDEBUG")) opts |= XrdSecDEBUG;
00861 if (getenv("XrdSecKRB5INITTKN")) opts |= XrdSecINITTKN;
00862 XrdSecProtocolkrb5::setClientOpts(opts);
00863 return (XrdSecProtocolkrb5::Init(erp) ? (char *)0 : (char *)"");
00864 }
00865
00866 if (!serverinitialized) {
00867 serverinitialized = true;
00868 }
00869
00870
00871
00872 if (parms) strlcpy(parmbuff, parms, sizeof(parmbuff));
00873 else {char *msg = (char *)"Seckrb5: Kerberos parameters not specified.";
00874 if (erp) erp->setErrInfo(EINVAL, msg);
00875 else cerr <<msg <<endl;
00876 return (char *)0;
00877 }
00878
00879
00880
00881 if (inParms.GetLine())
00882 {if ((op = inParms.GetToken()) && *op == '/')
00883 {Keytab = op; op = inParms.GetToken();}
00884 if (op && !strcmp(op, "-ipchk"))
00885 {options &= ~XrdSecNOIPCHK;
00886 op = inParms.GetToken();
00887 }
00888 if (op && !strncmp(op, "-exptkn", 7))
00889 {options |= XrdSecEXPTKN;
00890 if (op[7] == ':') ExpFile = op+8;
00891 op = inParms.GetToken();
00892 }
00893 KPrincipal = strdup(op);
00894 }
00895
00896 if (ExpFile)
00897 fprintf(stderr,"Template for exports: %s\n", ExpFile);
00898 else
00899 fprintf(stderr,"Template for exports not set\n");
00900
00901
00902
00903 if (!KPrincipal)
00904 {char *msg = (char *)"Seckrb5: Kerberos principal not specified.";
00905 if (erp) erp->setErrInfo(EINVAL, msg);
00906 else cerr <<msg <<endl;
00907 return (char *)0;
00908 }
00909
00910
00911
00912 int plen = strlen(KPrincipal);
00913 int lkey = strlen("<host>");
00914 char *phost = (char *) strstr(&KPrincipal[0], "<host>");
00915 if (phost)
00916 {char *hn = XrdNetDNS::getHostName();
00917 if (hn)
00918 {int lhn = strlen(hn);
00919 if (lhn != lkey) {
00920
00921 int lnew = plen - lkey + lhn;
00922 if (lnew > plen) {
00923 KPrincipal = (char *) realloc(KPrincipal, lnew+1);
00924 KPrincipal[lnew] = 0;
00925 phost = (char *) strstr(&KPrincipal[0], "<host>");
00926 }
00927
00928 int lm = plen - (int)(phost + lkey - &KPrincipal[0]);
00929 memmove(phost + lhn, phost + lkey, lm);
00930 }
00931
00932 memcpy(phost, hn, lhn);
00933
00934 free(hn);
00935 }
00936 }
00937
00938
00939
00940 options |= XrdSecDEBUG;
00941 XrdSecProtocolkrb5::setExpFile(ExpFile);
00942 XrdSecProtocolkrb5::setOpts(options);
00943 if (!XrdSecProtocolkrb5::Init(erp, KPrincipal, Keytab))
00944 {free(KPrincipal);
00945 int lpars = strlen(XrdSecProtocolkrb5::getPrincipal());
00946 if (options & XrdSecEXPTKN)
00947 lpars += strlen(",fwd");
00948 char *params = (char *)malloc(lpars+1);
00949 if (params)
00950 {memset(params,0,lpars+1);
00951 strcpy(params,XrdSecProtocolkrb5::getPrincipal());
00952 if (options & XrdSecEXPTKN)
00953 strcat(params,",fwd");
00954 XrdSecProtocolkrb5::setParms(params);
00955 return params;
00956 }
00957 }
00958
00959
00960
00961 free(KPrincipal);
00962 return (char *)0;
00963 }
00964 }
00965
00966
00967
00968
00969
00970 extern "C"
00971 {
00972 XrdSecProtocol *XrdSecProtocolkrb5Object(const char mode,
00973 const char *hostname,
00974 const struct sockaddr &netaddr,
00975 const char *parms,
00976 XrdOucErrInfo *erp)
00977 {
00978 XrdSecProtocolkrb5 *prot;
00979 char *KPrincipal=0;
00980
00981
00982
00983
00984
00985 if (mode == 'c')
00986 {if ((KPrincipal = (char *)parms)) while(*KPrincipal == ' ') KPrincipal++;
00987 if (!KPrincipal || !*KPrincipal)
00988 {char *msg = (char *)"Seckrb5: Kerberos principal not specified.";
00989 if (erp) erp->setErrInfo(EINVAL, msg);
00990 else cerr <<msg <<endl;
00991 return (XrdSecProtocol *)0;
00992 }
00993 }
00994
00995
00996
00997 if (!(prot = new XrdSecProtocolkrb5(KPrincipal, hostname, &netaddr)))
00998 {char *msg = (char *)"Seckrb5: Insufficient memory for protocol.";
00999 if (erp) erp->setErrInfo(ENOMEM, msg);
01000 else cerr <<msg <<endl;
01001 return (XrdSecProtocol *)0;
01002 }
01003
01004
01005
01006 return prot;
01007 }
01008
01009 void
01010 __eprintf (const char *string, const char *expression,
01011 unsigned int line, const char *filename)
01012 {
01013 fprintf (stderr, string, expression, line, filename);
01014 fflush (stderr);
01015 abort ();
01016 }
01017 }