47#ifdef HAVE_ET_COM_ERR_H
48#include "et/com_err.h"
54#include "XrdVersion.hh"
70#define krb_etxt(x) (char *)error_message(x)
72#define XrdSecPROTOIDENT "krb5"
73#define XrdSecPROTOIDLEN sizeof(XrdSecPROTOIDENT)
74#define XrdSecNOIPCHK 0x0001
75#define XrdSecEXPTKN 0x0002
76#define XrdSecINITTKN 0x0004
77#define XrdSecDEBUG 0x1000
79#define XrdSecMAXPATHLEN 4096
81#define CLDBG(x) if (client_options & XrdSecDEBUG) std::cerr <<"Seckrb5: " <<x <<std::endl;
82#define CLPRT(x) std::cerr <<"Seckrb5: " <<x <<std::endl;
111 {
int lt = strlen(expfile);
114 memcpy(ExpFile, expfile, lt);
123 {Service = (KP ? strdup(KP) : 0);
127 CName[0] =
'?'; CName[1] =
'\0';
131 AuthClientContext = 0;
143static int get_krbCreds(
char *KP, krb5_creds **krb_creds);
144 void SetAddr(krb5_address &ipadd);
149static int client_options;
150static krb5_context krb_context;
151static krb5_context krb_client_context;
152static krb5_ccache krb_client_ccache;
153static krb5_ccache krb_ccache;
154static krb5_keytab krb_keytab;
155static krb5_principal krb_principal;
157static char *Principal;
163int get_krbFwdCreds(
char *KP, krb5_data *outdata);
169krb5_auth_context AuthContext;
170krb5_auth_context AuthClientContext;
182int XrdSecProtocolkrb5::client_options = 0;
183int XrdSecProtocolkrb5::options = 0;
184krb5_context XrdSecProtocolkrb5::krb_context;
185krb5_context XrdSecProtocolkrb5::krb_client_context;
186krb5_ccache XrdSecProtocolkrb5::krb_client_ccache;
187krb5_ccache XrdSecProtocolkrb5::krb_ccache;
188krb5_keytab XrdSecProtocolkrb5::krb_keytab = NULL;
189krb5_principal XrdSecProtocolkrb5::krb_principal;
191char *XrdSecProtocolkrb5::Principal = 0;
192char *XrdSecProtocolkrb5::Parms = 0;
202 if (Parms) {free(Parms); Parms = 0;}
203 if (Creds) krb5_free_creds(krb_context, Creds);
204 if (Ticket) krb5_free_ticket(krb_context, Ticket);
205 if (AuthContext) krb5_auth_con_free(krb_context, AuthContext);
206 if (AuthClientContext) krb5_auth_con_free(krb_client_context, AuthClientContext);
208 if (Service) free(Service);
223 CLDBG(
"getCredentials");
227 {
CLDBG(
"Null credentials supplied.");
231 CLDBG(
"context lock");
232 krbClientContext.
Lock();
233 CLDBG(
"context locked");
237 char *ccn = (error && error->
getEnv()) ? error->
getEnv()->
Get(
"xrd.k5ccname") : 0;
238 const char *kccn = ccn ? (
const char *)ccn : getenv(
"KRB5CCNAME");
241 {snprintf(ccname, 128,
"/tmp/krb5cc_%d", geteuid());
242 if (
access(ccname, R_OK) == 0)
245 CLDBG((kccn ? kccn :
"credentials cache unset"));
249 if ((rc = krb5_init_context(&krb_client_context)))
250 {krbClientContext.
UnLock();
251 Fatal(error, ENOPROTOOPT,
"Kerberos initialization failed", Service, rc);
255 CLDBG(
"init context");
259 if ((rc = krb5_cc_set_default_name(krb_client_context, kccn)))
260 {krbClientContext.
UnLock();
261 Fatal(error, ENOPROTOOPT,
"Kerberos default credentials cache setting failed", Service, rc);
265 CLDBG(
"cc set default name");
269 if ((rc = krb5_cc_default(krb_client_context, &krb_client_ccache)))
270 {krbClientContext.
UnLock();
271 Fatal(error, ENOPROTOOPT,
"Unable to locate cred cache", Service, rc);
279 if ((pfwd = (
char *) strstr(Service,
",fwd")))
287 outbuf.length = 0; outbuf.data = 0;
295 {
if ((rc = get_krbFwdCreds(Service, &outbuf)))
296 {krbClientContext.
UnLock();
297 Fatal(error, ESRCH,
"Unable to get forwarded credentials", Service, rc);
301 if (!(buff = (
char *)malloc(bsz)))
302 {krbClientContext.
UnLock();
303 Fatal(error, ENOMEM,
"Insufficient memory for credentials.", Service);
308 (
const void *)outbuf.data, (
size_t)outbuf.length);
309 CLDBG(
"Returned " <<bsz <<
" bytes of creds; p=" <<Service);
310 if (outbuf.data) free(outbuf.data);
311 krbClientContext.
UnLock();
322 bool caninittkn = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
323 const char *reinitcmd = (client_options &
XrdSecEXPTKN) ?
"kinit -f" :
"kinit";
327 {
if ((rc = (
krb_rc)get_krbCreds(Service, &Creds)))
328 {
if (!(client_options &
XrdSecINITTKN) || reinitdone || !caninittkn)
329 {krbClientContext.
UnLock();
331 "No or invalid credentials" :
"Unable to get credentials";
332 Fatal(error, ESRCH, m, Service, rc);
335 CLPRT(
"Ticket missing or invalid: re-init ");
336 rc = system(reinitcmd);
337 CLDBG(
"getCredentials: return code from '"<<reinitcmd<<
345 if (!(Creds->ticket_flags & TKT_FLG_FORWARDABLE))
346 {
if ((client_options &
XrdSecINITTKN) && !reinitdone && caninittkn)
348 CLPRT(
"Existing ticket is not forwardable: re-init ");
349 rc = system(reinitcmd);
350 CLDBG(
"getCredentials: return code from '"<<reinitcmd<<
355 krbClientContext.
UnLock();
356 Fatal(error, ESRCH,
"Existing ticket is not forwardable: cannot continue",
368 if ((rc = krb5_auth_con_init(krb_client_context, &AuthClientContext)))
369 {krbClientContext.
UnLock();
370 Fatal(error, ESRCH,
"Unable to init a new auth context", Service, rc);
376 rc = krb5_mk_req_extended(krb_client_context, &AuthClientContext,
377 AP_OPTS_USE_SESSION_KEY,(krb5_data *)0, Creds,&outbuf);
385 if (!(buff = (
char *)malloc(bsz)))
386 {krbClientContext.
UnLock();
387 Fatal(error, ENOMEM,
"Insufficient memory for credentials.", Service);
392 (
const void *)outbuf.data, (
size_t)outbuf.length);
393 CLDBG(
"Returned " <<bsz <<
" bytes of creds; p=" <<Service);
394 if (outbuf.data) free(outbuf.data);
395 krbClientContext.
UnLock();
401 if (outbuf.data) free(outbuf.data);
402 krbClientContext.
UnLock();
403 Fatal(error, EACCES,
"Unable to get credentials", Service, rc);
436 "Authentication protocol id mismatch (%.4s != %.4s).",
442 CLDBG(
"protocol check");
445 sprintf(printit,
"Step is %d",Step);
451 {
if ((rc = exp_krbTkn(cred, error)))
452 iferror = (
char *)
"Unable to export the token to file";
455 return Fatal(error, EINVAL, iferror, Principal, rc);
462 CLDBG(
"protocol check");
475 CLDBG(
"Context Lock");
485 CLDBG(
"Context Locked");
488 iferror = (
char *)
"Unable to validate ip address;";
489 if (!(rc=krb5_auth_con_init(krb_context, &AuthContext)))
490 rc=krb5_auth_con_setaddrs(krb_context, AuthContext, NULL, &ipadd);
496 {
if ((rc = krb5_rd_req(krb_context, &AuthContext, &inbuf,
497 (krb5_const_principal)krb_principal,
498 krb_keytab, NULL, &Ticket)))
499 iferror = (
char *)
"Unable to authenticate credentials;";
500 else if ((rc = krb5_aname_to_localname(krb_context,
501 Ticket->enc_part2->client,
502 sizeof(CName)-1, CName)))
503 iferror = (
char *)
"Unable to extract client name;";
508 CName[
sizeof(CName)-1] =
'\0';
512 if (!rc && XrdSecProtocolkrb5::options &
XrdSecEXPTKN) {
516 int len = strlen(
"fwdtgt") + 1;
517 char *buf = (
char *) malloc(len);
518 memcpy(buf,
"fwdtgt", len-1);
530 return Fatal(error, EACCES, iferror, Principal, rc);
557 if ((rc = krb5_init_context(&krb_context)))
558 return Fatal(erp, ENOPROTOOPT,
"Kerberos initialization failed", KP, rc);
562 if ((rc = krb5_cc_default(krb_context, &krb_ccache)))
563 return Fatal(erp, ENOPROTOOPT,
"Unable to locate cred cache", KP, rc);
568 {
if ((rc = krb5_kt_resolve(krb_context, kfn, &krb_keytab)))
569 {snprintf(buff,
sizeof(buff),
"Unable to find keytab '%s';", kfn);
570 return Fatal(erp, ESRCH, buff, Principal, rc);
573 krb5_kt_default(krb_context, &krb_keytab);
578 char krb_kt_name[1024];
579 if ((rc = krb5_kt_get_name(krb_context, krb_keytab, &krb_kt_name[0], 1024)))
580 {snprintf(buff,
sizeof(buff),
"Unable to get keytab name;");
581 return Fatal(erp, ESRCH, buff, Principal, rc);
587 if ((rc = krb5_kt_start_seq_get(krb_context, krb_keytab, &ktc)))
588 {snprintf(buff,
sizeof(buff),
"Unable to start sequence on the keytab file %s", krb_kt_name);
589 return Fatal(erp, EPERM, buff, Principal, rc);
591 if ((rc = krb5_kt_end_seq_get(krb_context, krb_keytab, &ktc)))
592 {snprintf(buff,
sizeof(buff),
"WARNING: unable to end sequence on the keytab file %s", krb_kt_name);
598 if ((rc = krb5_parse_name(krb_context,KP,&krb_principal)))
599 return Fatal(erp, EINVAL,
"Cannot parse service name", KP, rc);
603 if ((rc = krb5_unparse_name(krb_context,(krb5_const_principal)krb_principal,
604 (
char **)&Principal)))
605 return Fatal(erp, EINVAL,
"Unable to unparse principal;", KP, rc);
619int XrdSecProtocolkrb5::Fatal(
XrdOucErrInfo *erp,
int rc,
const char *msg,
625 msgv[i++] =
"Seckrb5: ";
627 if (krc) {msgv[i++] =
"; ";
630 if (KP) {msgv[i++] =
" (p=";
635 else {
for (k = 0; k < i; k++) std::cerr <<msgv[k];
636 std::cerr <<std::endl;
648int XrdSecProtocolkrb5::get_krbCreds(
char *KP, krb5_creds **krb_creds)
651 krb5_principal the_principal;
656 memset((
char *)&mycreds, 0,
sizeof(mycreds));
660 if ((rc = krb5_parse_name(krb_client_context,KP,&the_principal)))
661 {
CLDBG(
"get_krbCreds: Cannot parse service name;" <<
krb_etxt(rc));
667 if ((rc = krb5_copy_principal(krb_client_context, the_principal, &mycreds.server)))
668 {
CLDBG(
"get_krbCreds: err copying principal to creds; " <<
krb_etxt(rc));
669 krb5_free_principal(krb_client_context, the_principal);
675 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &mycreds.client)))
676 {
CLDBG(
"get_krbCreds: err copying client name to creds; " <<
krb_etxt(rc));
677 krb5_free_cred_contents(krb_client_context, &mycreds);
678 krb5_free_principal(krb_client_context, the_principal);
684 rc = krb5_get_credentials(krb_client_context, 0, krb_client_ccache, &mycreds, krb_creds);
685 krb5_free_cred_contents(krb_client_context, &mycreds);
686 krb5_free_principal(krb_client_context, the_principal);
690 if (rc) {
CLDBG(
"get_krbCreds: unable to get creds; " <<
krb_etxt(rc));}
698int XrdSecProtocolkrb5::get_krbFwdCreds(
char *KP, krb5_data *outdata)
701 krb5_principal client, server;
705 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &client)))
706 {
CLDBG(
"get_krbFwdCreds: err filling client principal; " <<
krb_etxt(rc));
712 if ((rc = krb5_parse_name(krb_client_context, KP, &server)))
713 {
CLDBG(
"get_krbFwdCreds: Cannot parse service principal;" <<
krb_etxt(rc));
719 if ((rc = krb5_auth_con_setflags(krb_client_context, AuthClientContext,
720 KRB5_AUTH_CONTEXT_RET_TIME)))
721 {
CLDBG(
"Unable to set KRB5_AUTH_CONTEXT_RET_TIME"
722 " in the authentication context" <<
krb_etxt(rc));
728 if ((rc = krb5_fwd_tgt_creds(krb_client_context, AuthClientContext, 0 ,
729 client, server, krb_client_ccache,
true,
731 {
CLDBG(
"get_krbFwdCreds: err getting forwarded ticket;" <<
krb_etxt(rc));
752 strcpy(ccfile, XrdSecProtocolkrb5::ExpFile);
753 int nlen = strlen(ccfile);
754 char *pusr = (
char *) strstr(&ccfile[0],
"<user>");
756 {
int ln = strlen(CName);
759 int lm = strlen(ccfile) - (int)(pusr + 6 - &ccfile[0]);
760 memmove(pusr+ln, pusr+6, lm);
763 memcpy(pusr, CName, ln);
767 char *puid = (
char *) strstr(&ccfile[0],
"<uid>");
771 {
char cuid[20] = {0};
773 sprintf(cuid,
"%d", pw->pw_uid);
774 int ln = strlen(cuid);
777 int lm = strlen(ccfile) - (int)(puid + 5 - &ccfile[0]);
778 memmove(puid+ln, pusr+5, lm);
781 memcpy(puid, cuid, ln);
793 krb5_data forwardCreds;
800 if ((rc = krb5_get_server_rcache(krb_context,
801 krb5_princ_component(krb_context, krb_principal, 0),
804 if ((rc = krb5_auth_con_setrcache(krb_context, AuthContext, rcache)))
810 if ((rc = krb5_auth_con_setaddrs(krb_context, AuthContext, 0, &ipadd)))
815 krb5_creds **creds = 0;
816 if ((rc = krb5_rd_cred(krb_context, AuthContext,
817 &forwardCreds, &creds, 0)))
821 krb5_ccache cache = 0;
822 if ((rc = krb5_cc_resolve(krb_context, ccfile, &cache)))
827 if ((rc = krb5_cc_initialize(krb_context, cache,
828 Ticket->enc_part2->client)))
833 if ((rc = krb5_cc_store_cred(krb_context, cache, *creds)))
837 if ((rc = krb5_cc_close(krb_context, cache)))
842 if (chmod(ccfile, 0600) == -1)
843 return Fatal(erp, errno,
"Unable to change file permissions;", ccfile, 0);
854void XrdSecProtocolkrb5::SetAddr(krb5_address &ipadd)
858 if (epAddr.
Family() == AF_INET6)
859 {
struct sockaddr_in6 *ip = (
struct sockaddr_in6 *)epAddr.
SockAddr();
860 ipadd.addrtype = ADDRTYPE_INET6;
861 ipadd.length =
sizeof(ip->sin6_addr);
862 ipadd.contents = (krb5_octet *)&ip->sin6_addr;
864 struct sockaddr_in *ip = (
struct sockaddr_in *)epAddr.
SockAddr();
865 ipadd.addrtype = ADDRTYPE_INET;
866 ipadd.length =
sizeof(ip->sin_addr);
867 ipadd.contents = (krb5_octet *)&ip->sin_addr;
881 char *op, *KPrincipal=0, *Keytab=0, *ExpFile=0;
885 static bool serverinitialized =
false;
890 if ((mode ==
'c') || (serverinitialized))
899 if (!serverinitialized) {
900 serverinitialized =
true;
905 if (parms)
strlcpy(parmbuff, parms,
sizeof(parmbuff));
906 else {
char *msg = (
char *)
"Seckrb5: Kerberos parameters not specified.";
908 else std::cerr <<msg <<std::endl;
915 {
if ((op = inParms.
GetToken()) && *op ==
'/')
916 {Keytab = op; op = inParms.
GetToken();}
917 if (op && !strcmp(op,
"-ipchk"))
918 {options &= ~XrdSecNOIPCHK;
921 if (op && !strncmp(op,
"-exptkn", 7))
923 if (op[7] ==
':') ExpFile = op+8;
926 KPrincipal = strdup(op);
930 fprintf(stderr,
"Template for exports: %s\n", ExpFile);
932 fprintf(stderr,
"Template for exports not set\n");
937 {
char *msg = (
char *)
"Seckrb5: Kerberos principal not specified.";
939 else std::cerr <<msg <<std::endl;
945 int plen = strlen(KPrincipal);
946 int lkey = strlen(
"<host>");
947 char *phost = (
char *) strstr(&KPrincipal[0],
"<host>");
951 {
int lhn = strlen(hn);
954 int lnew = plen - lkey + lhn;
956 KPrincipal = (
char *) realloc(KPrincipal, lnew+1);
957 KPrincipal[lnew] = 0;
958 phost = (
char *) strstr(&KPrincipal[0],
"<host>");
961 int lm = plen - (int)(phost + lkey - &KPrincipal[0]);
962 memmove(phost + lhn, phost + lkey, lm);
965 memcpy(phost, hn, lhn);
980 lpars += strlen(
",fwd");
981 char *params = (
char *)malloc(lpars+1);
983 {memset(params,0,lpars+1);
986 strcat(params,
",fwd");
1007 const char *hostname,
1020 {
if ((KPrincipal = (
char *)parms))
while(*KPrincipal ==
' ') KPrincipal++;
1021 if (!KPrincipal || !*KPrincipal)
1022 {
char *msg = (
char *)
"Seckrb5: Kerberos principal not specified.";
1024 else std::cerr <<msg <<std::endl;
1032 {
char *msg = (
char *)
"Seckrb5: Insufficient memory for protocol.";
1034 else std::cerr <<msg <<std::endl;
1045 unsigned int line,
const char *filename)
1047 fprintf (stderr,
string, expression, line, filename);
XrdVERSIONINFO(XrdClGetPlugIn, XrdClGetPlugIn) extern "C"
void Fatal(const char *op, const char *target)
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
char * XrdSecProtocolkrb5Init(const char mode, const char *parms, XrdOucErrInfo *erp)
XrdSecProtocol * XrdSecProtocolkrb5Object(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
void __eprintf(const char *string, const char *expression, unsigned int line, const char *filename)
int emsg(int rc, char *msg)
const sockaddr * SockAddr()
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
char * Get(const char *varname)
int setErrInfo(int code, const char *emsg)
char * GetToken(char **rest=0, int lowcase=0)
XrdNetAddrInfo * addrInfo
Entity's connection details.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * name
Entity's name.
char * host
Entity's host name dnr dependent.
int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)
XrdSecProtocolkrb5(const char *KP, const char *hname, XrdNetAddrInfo &endPoint)
void Delete()
Delete the protocol object. DO NOT use C++ delete() on this object.
static char * getPrincipal()
static void setOpts(int opts)
static void setClientOpts(int opts)
static void setExpFile(char *expfile)
static void setParms(char *param)
static int Init(XrdOucErrInfo *einfo, char *KP=0, char *kfn=0)
XrdSecCredentials * getCredentials(XrdSecParameters *parm=0, XrdOucErrInfo *einfo=0)
friend class XrdSecProtocolDummy
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.