41 #include <sys/param.h>
43 #include <sys/types.h>
48 #ifdef HAVE_ET_COM_ERR_H
49 #include "et/com_err.h"
55 #include "XrdVersion.hh"
71 #define krb_etxt(x) (char *)error_message(x)
73 #define XrdSecPROTOIDENT "krb5"
74 #define XrdSecPROTOIDLEN sizeof(XrdSecPROTOIDENT)
75 #define XrdSecNOIPCHK 0x0001
76 #define XrdSecEXPTKN 0x0002
77 #define XrdSecINITTKN 0x0004
78 #define XrdSecDEBUG 0x1000
80 #define XrdSecMAXPATHLEN 4096
82 #define CLDBG(x) if (client_options & XrdSecDEBUG) std::cerr <<"Seckrb5: " <<x <<std::endl;
83 #define CLPRT(x) std::cerr <<"Seckrb5: " <<x <<std::endl;
112 {
int lt = strlen(expfile);
115 memcpy(ExpFile, expfile, lt);
124 {
Service = (KP ? strdup(KP) : 0);
128 CName[0] =
'?'; CName[1] =
'\0';
132 AuthClientContext = 0;
144 const char *KP=0,
int krc=0,
bool isClient=
false);
145 static int get_krbCreds(
char *KP, krb5_creds **krb_creds);
146 void SetAddr(krb5_address &ipadd);
151 static int client_options;
152 static krb5_context krb_context;
153 static krb5_context krb_client_context;
154 static krb5_ccache krb_client_ccache;
155 static krb5_ccache krb_ccache;
156 static krb5_keytab krb_keytab;
157 static krb5_principal krb_principal;
159 static char *Principal;
165 int get_krbFwdCreds(
char *KP, krb5_data *outdata);
171 krb5_auth_context AuthContext;
172 krb5_auth_context AuthClientContext;
184 int XrdSecProtocolkrb5::client_options = 0;
185 int XrdSecProtocolkrb5::options = 0;
186 krb5_context XrdSecProtocolkrb5::krb_context;
187 krb5_context XrdSecProtocolkrb5::krb_client_context;
188 krb5_ccache XrdSecProtocolkrb5::krb_client_ccache;
189 krb5_ccache XrdSecProtocolkrb5::krb_ccache;
190 krb5_keytab XrdSecProtocolkrb5::krb_keytab = NULL;
191 krb5_principal XrdSecProtocolkrb5::krb_principal;
193 char *XrdSecProtocolkrb5::Principal = 0;
194 char *XrdSecProtocolkrb5::Parms = 0;
204 if (Parms) {free(Parms); Parms = 0;}
205 if (Creds) krb5_free_creds(krb_context, Creds);
206 if (Ticket) krb5_free_ticket(krb_context, Ticket);
207 if (AuthContext) krb5_auth_con_free(krb_context, AuthContext);
208 if (AuthClientContext) krb5_auth_con_free(krb_client_context, AuthClientContext);
225 CLDBG(
"getCredentials");
229 {
CLDBG(
"Null credentials supplied.");
233 CLDBG(
"context lock");
234 krbClientContext.
Lock();
235 CLDBG(
"context locked");
239 char *ccn = (error && error->
getEnv()) ? error->
getEnv()->
Get(
"xrd.k5ccname") : 0;
240 const char *kccn = ccn ? (
const char *)ccn : getenv(
"KRB5CCNAME");
243 {snprintf(ccname, 128,
"/tmp/krb5cc_%d", geteuid());
244 if (
access(ccname, R_OK) == 0)
247 CLDBG((kccn ? kccn :
"credentials cache unset"));
251 if ((rc = krb5_init_context(&krb_client_context)))
252 {krbClientContext.
UnLock();
253 Fatal(error, ENOPROTOOPT,
"Kerberos initialization failed",
Service, rc);
257 CLDBG(
"init context");
261 if ((rc = krb5_cc_set_default_name(krb_client_context, kccn)))
262 {krbClientContext.
UnLock();
263 Fatal(error, ENOPROTOOPT,
"Kerberos default credentials cache setting failed",
Service, rc);
267 CLDBG(
"cc set default name");
271 if ((rc = krb5_cc_default(krb_client_context, &krb_client_ccache)))
272 {krbClientContext.
UnLock();
273 Fatal(error, ENOPROTOOPT,
"Unable to locate cred cache",
Service, rc);
281 if ((pfwd = (
char *) strstr(
Service,
",fwd")))
289 outbuf.length = 0; outbuf.data = 0;
297 {
if ((rc = get_krbFwdCreds(
Service, &outbuf)))
298 {krbClientContext.
UnLock();
299 Fatal(error, ESRCH,
"Unable to get forwarded credentials",
Service, rc);
303 if (!(buff = (
char *)malloc(bsz)))
304 {krbClientContext.
UnLock();
305 Fatal(error, ENOMEM,
"Insufficient memory for credentials.",
Service);
310 (
const void *)outbuf.data, (
size_t)outbuf.length);
311 CLDBG(
"Returned " <<bsz <<
" bytes of creds; p=" <<
Service);
312 if (outbuf.data) free(outbuf.data);
313 krbClientContext.
UnLock();
324 bool caninittkn = (isatty(0) == 0 || isatty(1) == 0) ? 0 : 1;
325 const char *reinitcmd = (client_options &
XrdSecEXPTKN) ?
"kinit -f" :
"kinit";
330 {
if (!(client_options &
XrdSecINITTKN) || reinitdone || !caninittkn)
331 {krbClientContext.
UnLock();
333 "No or invalid credentials" :
"Unable to get credentials";
337 CLPRT(
"Ticket missing or invalid: re-init ");
338 rc = system(reinitcmd);
339 CLDBG(
"getCredentials: return code from '"<<reinitcmd<<
347 if (!(Creds->ticket_flags & TKT_FLG_FORWARDABLE))
348 {
if ((client_options &
XrdSecINITTKN) && !reinitdone && caninittkn)
350 CLPRT(
"Existing ticket is not forwardable: re-init ");
351 rc = system(reinitcmd);
352 CLDBG(
"getCredentials: return code from '"<<reinitcmd<<
357 krbClientContext.
UnLock();
358 Fatal(error, ESRCH,
"Existing ticket is not forwardable: cannot continue",
370 if ((rc = krb5_auth_con_init(krb_client_context, &AuthClientContext)))
371 {krbClientContext.
UnLock();
372 Fatal(error, ESRCH,
"Unable to init a new auth context",
Service, rc);
378 rc = krb5_mk_req_extended(krb_client_context, &AuthClientContext,
379 AP_OPTS_USE_SESSION_KEY,(krb5_data *)0, Creds,&outbuf);
387 if (!(buff = (
char *)malloc(bsz)))
388 {krbClientContext.
UnLock();
389 Fatal(error, ENOMEM,
"Insufficient memory for credentials.",
Service);
394 (
const void *)outbuf.data, (
size_t)outbuf.length);
395 CLDBG(
"Returned " <<bsz <<
" bytes of creds; p=" <<
Service);
396 if (outbuf.data) free(outbuf.data);
397 krbClientContext.
UnLock();
403 if (outbuf.data) free(outbuf.data);
404 krbClientContext.
UnLock();
405 Fatal(error, EACCES,
"Unable to get credentials",
Service, rc);
423 const char *iferror = 0;
424 std::string cPrincipal;
440 "Authentication protocol id mismatch (%.4s != %.4s).",
446 CLDBG(
"protocol check");
449 sprintf(printit,
"Step is %d",Step);
455 {
if ((rc = exp_krbTkn(cred, error)))
456 iferror =
"Unable to export the token to file";
459 return Fatal(error, EINVAL, iferror, Principal, rc);
466 CLDBG(
"protocol check");
479 CLDBG(
"Context Lock");
489 CLDBG(
"Context Locked");
492 iferror =
"Unable to validate ip address;";
493 if (!(rc=krb5_auth_con_init(krb_context, &AuthContext)))
494 rc=krb5_auth_con_setaddrs(krb_context, AuthContext, NULL, &ipadd);
500 {
if ((rc = krb5_rd_req(krb_context, &AuthContext, &inbuf,
501 (krb5_const_principal)krb_principal,
502 krb_keytab, NULL, &Ticket)))
503 iferror =
"Unable to authenticate credentials;";
504 else if ((rc = krb5_aname_to_localname(krb_context,
505 Ticket->enc_part2->client,
506 sizeof(CName)-1, CName)))
507 iferror =
"Unable to get client localname";
513 if (!Ticket || !Ticket->enc_part2)
514 cPrincipal =
"[principal not available]";
515 else if ((
ec = krb5_unparse_name(krb_context,
516 (krb5_const_principal)Ticket->enc_part2->client,
519 snprintf(mBuff,
sizeof(mBuff),
520 "[principal unparse failed; %s]",
krb_etxt(
ec));
524 krb5_free_unparsed_name(krb_context, cpName);
531 CName[
sizeof(CName)-1] =
'\0';
535 if (!rc && XrdSecProtocolkrb5::options &
XrdSecEXPTKN) {
539 int len = strlen(
"fwdtgt") + 1;
540 char *buf = (
char *) malloc(len);
541 memcpy(buf,
"fwdtgt", len-1);
553 return Fatal(error, EACCES, iferror,
554 (isCP ? cPrincipal.c_str() : Principal), rc, isCP);
581 if ((rc = krb5_init_context(&krb_context)))
582 return Fatal(erp, ENOPROTOOPT,
"Kerberos initialization failed", KP, rc);
586 if ((rc = krb5_cc_default(krb_context, &krb_ccache)))
587 return Fatal(erp, ENOPROTOOPT,
"Unable to locate cred cache", KP, rc);
592 {
if ((rc = krb5_kt_resolve(krb_context, kfn, &krb_keytab)))
593 {snprintf(buff,
sizeof(buff),
"Unable to find keytab '%s';", kfn);
594 return Fatal(erp, ESRCH, buff, Principal, rc);
597 krb5_kt_default(krb_context, &krb_keytab);
602 char krb_kt_name[1024];
603 if ((rc = krb5_kt_get_name(krb_context, krb_keytab, &krb_kt_name[0], 1024)))
604 {snprintf(buff,
sizeof(buff),
"Unable to get keytab name;");
605 return Fatal(erp, ESRCH, buff, Principal, rc);
611 if ((rc = krb5_kt_start_seq_get(krb_context, krb_keytab, &ktc)))
612 {snprintf(buff,
sizeof(buff),
"Unable to start sequence on the keytab file %s", krb_kt_name);
613 return Fatal(erp, EPERM, buff, Principal, rc);
615 if ((rc = krb5_kt_end_seq_get(krb_context, krb_keytab, &ktc)))
616 {snprintf(buff,
sizeof(buff),
"WARNING: unable to end sequence on the keytab file %s", krb_kt_name);
622 if ((rc = krb5_parse_name(krb_context,KP,&krb_principal)))
623 return Fatal(erp, EINVAL,
"Cannot parse service principal name", KP, rc);
627 if ((rc = krb5_unparse_name(krb_context,(krb5_const_principal)krb_principal,
628 (
char **)&Principal)))
629 return Fatal(erp, EINVAL,
"Unable to unparse service principal;", KP, rc);
643 int XrdSecProtocolkrb5::Fatal(
XrdOucErrInfo *erp,
int rc,
const char *msg,
644 const char *KP,
int krc,
bool isClient)
649 msgv[i++] =
"Seckrb5: ";
651 if (krc) {msgv[i++] =
"; ";
654 if (KP) {
const char* who = (isClient ?
"(client=" :
"(server=");
660 else {
for (k = 0; k < i; k++) std::cerr <<msgv[k];
661 std::cerr <<std::endl;
673 int XrdSecProtocolkrb5::get_krbCreds(
char *KP, krb5_creds **krb_creds)
676 krb5_principal the_principal;
681 memset((
char *)&mycreds, 0,
sizeof(mycreds));
685 if ((rc = krb5_parse_name(krb_client_context,KP,&the_principal)))
686 {
CLDBG(
"get_krbCreds: Cannot parse service name;" <<
krb_etxt(rc));
692 if ((rc = krb5_copy_principal(krb_client_context, the_principal, &mycreds.server)))
693 {
CLDBG(
"get_krbCreds: err copying principal to creds; " <<
krb_etxt(rc));
694 krb5_free_principal(krb_client_context, the_principal);
700 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &mycreds.client)))
701 {
CLDBG(
"get_krbCreds: err copying client name to creds; " <<
krb_etxt(rc));
702 krb5_free_cred_contents(krb_client_context, &mycreds);
703 krb5_free_principal(krb_client_context, the_principal);
709 rc = krb5_get_credentials(krb_client_context, 0, krb_client_ccache, &mycreds, krb_creds);
710 krb5_free_cred_contents(krb_client_context, &mycreds);
711 krb5_free_principal(krb_client_context, the_principal);
715 if (rc) {
CLDBG(
"get_krbCreds: unable to get creds; " <<
krb_etxt(rc));}
723 int XrdSecProtocolkrb5::get_krbFwdCreds(
char *KP, krb5_data *outdata)
726 krb5_principal client, server;
730 if ((rc = krb5_cc_get_principal(krb_client_context, krb_client_ccache, &client)))
731 {
CLDBG(
"get_krbFwdCreds: err filling client principal; " <<
krb_etxt(rc));
737 if ((rc = krb5_parse_name(krb_client_context, KP, &server)))
738 {
CLDBG(
"get_krbFwdCreds: Cannot parse service principal;" <<
krb_etxt(rc));
744 if ((rc = krb5_auth_con_setflags(krb_client_context, AuthClientContext,
745 KRB5_AUTH_CONTEXT_RET_TIME)))
746 {
CLDBG(
"Unable to set KRB5_AUTH_CONTEXT_RET_TIME"
747 " in the authentication context" <<
krb_etxt(rc));
753 if ((rc = krb5_fwd_tgt_creds(krb_client_context, AuthClientContext, 0 ,
754 client, server, krb_client_ccache,
true,
756 {
CLDBG(
"get_krbFwdCreds: err getting forwarded ticket;" <<
krb_etxt(rc));
777 strcpy(ccfile, XrdSecProtocolkrb5::ExpFile);
778 int nlen = strlen(ccfile);
779 char *pusr = (
char *) strstr(&ccfile[0],
"<user>");
781 {
int ln = strlen(CName);
784 int lm = strlen(ccfile) - (int)(pusr + 6 - &ccfile[0]);
785 memmove(pusr+ln, pusr+6, lm);
788 memcpy(pusr, CName, ln);
792 char *puid = (
char *) strstr(&ccfile[0],
"<uid>");
796 {
char cuid[20] = {0};
798 sprintf(cuid,
"%d", pw->pw_uid);
799 int ln = strlen(cuid);
802 int lm = strlen(ccfile) - (int)(puid + 5 - &ccfile[0]);
803 memmove(puid+ln, pusr+5, lm);
806 memcpy(puid, cuid, ln);
818 krb5_data forwardCreds;
825 if ((rc = krb5_get_server_rcache(krb_context,
826 krb5_princ_component(krb_context, krb_principal, 0),
829 if ((rc = krb5_auth_con_setrcache(krb_context, AuthContext, rcache)))
835 if ((rc = krb5_auth_con_setaddrs(krb_context, AuthContext, 0, &ipadd)))
840 krb5_creds **creds = 0;
841 if ((rc = krb5_rd_cred(krb_context, AuthContext,
842 &forwardCreds, &creds, 0)))
846 krb5_ccache cache = 0;
847 if ((rc = krb5_cc_resolve(krb_context, ccfile, &cache)))
852 if ((rc = krb5_cc_initialize(krb_context, cache,
853 Ticket->enc_part2->client)))
858 if ((rc = krb5_cc_store_cred(krb_context, cache, *creds)))
862 if ((rc = krb5_cc_close(krb_context, cache)))
867 if (chmod(ccfile, 0600) == -1)
868 return Fatal(erp, errno,
"Unable to change file permissions;", ccfile, 0);
879 void XrdSecProtocolkrb5::SetAddr(krb5_address &ipadd)
883 if (epAddr.
Family() == AF_INET6)
884 {
struct sockaddr_in6 *ip = (
struct sockaddr_in6 *)epAddr.
SockAddr();
885 ipadd.addrtype = ADDRTYPE_INET6;
886 ipadd.length =
sizeof(ip->sin6_addr);
887 ipadd.contents = (krb5_octet *)&ip->sin6_addr;
889 struct sockaddr_in *ip = (
struct sockaddr_in *)epAddr.
SockAddr();
890 ipadd.addrtype = ADDRTYPE_INET;
891 ipadd.length =
sizeof(ip->sin_addr);
892 ipadd.contents = (krb5_octet *)&ip->sin_addr;
906 char *op, *KPrincipal=0, *Keytab=0, *ExpFile=0;
910 static bool serverinitialized =
false;
915 if ((mode ==
'c') || (serverinitialized))
924 if (!serverinitialized) {
925 serverinitialized =
true;
930 if (parms)
strlcpy(parmbuff, parms,
sizeof(parmbuff));
931 else {
char *msg = (
char *)
"Seckrb5: Kerberos parameters not specified.";
933 else std::cerr <<msg <<std::endl;
940 {
if ((op = inParms.
GetToken()) && *op ==
'/')
941 {Keytab = op; op = inParms.
GetToken();}
942 if (op && !strcmp(op,
"-ipchk"))
946 if (op && !strncmp(op,
"-exptkn", 7))
948 if (op[7] ==
':') ExpFile = op+8;
951 KPrincipal = strdup(op);
955 fprintf(stderr,
"Template for exports: %s\n", ExpFile);
957 fprintf(stderr,
"Template for exports not set\n");
962 {
char *msg = (
char *)
"Seckrb5: Kerberos principal not specified.";
964 else std::cerr <<msg <<std::endl;
970 int plen = strlen(KPrincipal);
971 int lkey = strlen(
"<host>");
972 char *phost = (
char *) strstr(&KPrincipal[0],
"<host>");
976 {
int lhn = strlen(hn);
979 int lnew = plen - lkey + lhn;
981 KPrincipal = (
char *) realloc(KPrincipal, lnew+1);
982 KPrincipal[lnew] = 0;
983 phost = (
char *) strstr(&KPrincipal[0],
"<host>");
986 int lm = plen - (int)(phost + lkey - &KPrincipal[0]);
987 memmove(phost + lhn, phost + lkey, lm);
990 memcpy(phost, hn, lhn);
1005 lpars += strlen(
",fwd");
1006 char *params = (
char *)malloc(lpars+1);
1008 {memset(params,0,lpars+1);
1011 strcat(params,
",fwd");
1032 const char *hostname,
1045 {
if ((KPrincipal = (
char *)parms))
while(*KPrincipal ==
' ') KPrincipal++;
1046 if (!KPrincipal || !*KPrincipal)
1047 {
char *msg = (
char *)
"Seckrb5: Kerberos principal not specified.";
1049 else std::cerr <<msg <<std::endl;
1057 {
char *msg = (
char *)
"Seckrb5: Insufficient memory for protocol.";
1059 else std::cerr <<msg <<std::endl;
1070 unsigned int line,
const char *filename)
1072 fprintf (stderr,
string, expression, line, filename);
XrdVERSIONINFO(XrdClGetPlugIn, XrdClGetPlugIn) extern "C"
void Fatal(const char *op, const char *target)
int access(const char *path, int amode)
XrdSecBuffer XrdSecParameters
XrdSecBuffer XrdSecCredentials
XrdSecProtocol * XrdSecProtocolkrb5Object(const char mode, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *erp)
char * XrdSecProtocolkrb5Init(const char mode, 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 void setOpts(int opts)
static void setClientOpts(int opts)
static char * getPrincipal()
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.