Logo ROOT   6.07/09
Reference Guide
Krb5Auth.cxx
Go to the documentation of this file.
1 // @(#)root/krb5auth:$Id$
2 // Author: Johannes Muelmenstaedt 17/03/2002
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /* Parts of this file are copied from the MIT krb5 distribution and
13  * are subject to the following license:
14  *
15  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
16  * All Rights Reserved.
17  *
18  * Export of this software from the United States of America may
19  * require a specific license from the United States Government.
20  * It is the responsibility of any person or organization contemplating
21  * export to obtain such a license before exporting.
22  *
23  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
24  * distribute this software and its documentation for any purpose and
25  * without fee is hereby granted, provided that the above copyright
26  * notice appear in all copies and that both that copyright notice and
27  * this permission notice appear in supporting documentation, and that
28  * the name of M.I.T. not be used in advertising or publicity pertaining
29  * to distribution of the software without specific, written prior
30  * permission. Furthermore if you modify this software you must label
31  * your software as modified software and not distribute it in such a
32  * fashion that it might be confused with the original M.I.T. software.
33  * M.I.T. makes no representations about the suitability of
34  * this software for any purpose. It is provided "as is" without express
35  * or implied warranty.
36  *
37  */
38 
39 #include <errno.h>
40 #include <signal.h>
41 #include <string.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netdb.h>
45 #include <time.h>
46 
47 #include "Krb5Auth.h"
48 #include "TSocket.h"
49 #include "TAuthenticate.h"
50 #include "TDatime.h"
51 #include "TROOT.h"
52 #include "THostAuth.h"
53 #include "TError.h"
54 #include "TSystem.h"
55 #include "TEnv.h"
56 #include "NetErrors.h"
57 #include "Getline.h"
58 
59 #if defined(R__KRB5_NEED_VCST_DEFINE)
60 #define krb5_c_valid_cksumtype valid_cksumtype
61 #endif
62 #if defined(R__KRB5_NEED_VCST_PROTO)
63 krb5_boolean krb5_c_valid_cksumtype(krb5_cksumtype ctype);
64 #endif
65 
67 
68 static Int_t Krb5InitCred(const char *clientPrincipal, Bool_t promptPrinc = kFALSE);
69 static Int_t Krb5CheckCred(krb5_context, krb5_ccache, TString, TDatime &);
70 static Int_t Krb5CheckSecCtx(const char *, TRootSecContext *);
71 
72 class TKrb5AuthInit {
73 public:
75 };
76 static TKrb5AuthInit gKrb5authInit;
77 
78 class TKrb5CleanUp {
79 public:
80  Bool_t fSignal;
81  krb5_context fContext;
82  krb5_ccache fCcdef;
83  krb5_principal fClient;
84  krb5_principal fServer;
85  krb5_auth_context fAuthContext;
86  krb5_ap_rep_enc_part *fRepRet;
87  char *fData;
88 
89  TKrb5CleanUp() : fSignal(false), fContext(0), fCcdef(0), fClient(0),
90  fServer(0), fAuthContext(0), fRepRet(0), fData(0) {
91  }
92 
93  ~TKrb5CleanUp() {
94  if (fSignal) gSystem->IgnoreSignal(kSigPipe, kFALSE);
95 
96  if (fData) free(fData);
97  if (fRepRet) krb5_free_ap_rep_enc_part(fContext, fRepRet);
98 
99  if (fAuthContext) krb5_auth_con_free(fContext, fAuthContext);
100 
101  if (fServer) krb5_free_principal(fContext, fServer);
102  if (fClient) krb5_free_principal(fContext, fClient);
103 
104 
105  if (fCcdef) krb5_cc_close(fContext, fCcdef);
106  if (fContext) krb5_free_context(fContext);
107  }
108 };
109 
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// Kerberos v5 authentication code. Returns 0 in case authentication
113 /// failed, 1 in case of success and 2 in case remote does not support
114 /// Kerberos5.
115 /// Protocol 'version': 3 supports alternate username
116 /// 2 supports negotiation and auth reuse
117 /// 1 first kerberos implementation
118 /// 0 no kerberos support (function should not be called)
119 /// user is used to input the target username and return the name in the
120 /// principal used
121 
123  Int_t version)
124 {
125 
126  TKrb5CleanUp cleanup;
127 
128  int retval;
129  int kind;
130  TSocket *sock = auth->GetSocket();
131 
132  char answer[256];
133  int type;
134  Int_t nsen = 0, nrec = 0;
135 
136  TString targetUser(user);
137  TString localUser;
138  // The default will be the one related to the logged user
140  if (u) {
141  localUser = u->fUser;
142  delete u;
143  } else
144  localUser = TAuthenticate::GetDefaultUser();
145  Bool_t promptPrinc = (targetUser != localUser);
146 
147  // first check if protocol version supports kerberos, krb5 support
148  // was introduced in rootd version 6
149  // This checked in the calling rootines and the result is contained in
150  // the argument 'version'
151  if (version <= 0) return 2; // ... but you shouldn't have got here ...
152 
153  // get a context
154  krb5_context context;
155  retval = krb5_init_context(&context);
156  cleanup.fContext = context;
157 
158  if (retval) {
159  Error("Krb5Authenticate","failed <krb5_init_context>: %s\n",
160  error_message(retval));
161  return -1;
162  }
163 
164  // ignore broken connection signal handling
166  cleanup.fSignal = kTRUE;
167 
168  // get our credentials cache
169  krb5_ccache ccdef;
170  if (gDebug > 2) {
171  if (gSystem->Getenv("KRB5CCNAME"))
172  Info("Krb5Authenticate",
173  "Use credential file from $KRB5CCNAME: %s\n",
174  gSystem->Getenv("KRB5CCNAME"));
175  else
176  Info("Krb5Authenticate",
177  "Use default credential file ($KRB5CCNAME undefined)");
178  }
179  if ((retval = krb5_cc_default(context, &ccdef))) {
180  Error("Krb5Authenticate","failed <krb5_cc_default>: %s\n",
181  error_message(retval));
182  return -1;
183  }
184  cleanup.fCcdef = ccdef;
185 
186  // get our principal from the cache
187  krb5_principal client;
189  Bool_t gotPrincipal = (principal.Length() > 0) ? kTRUE : kFALSE;
190  //
191  // if not defined or incomplete, complete with defaults;
192  // but only if interactive
193  if (!principal.Length() || !principal.Contains("@")) {
194  if (gDebug > 3)
195  Info("Krb5Authenticate",
196  "incomplete principal: complete using defaults");
197  krb5_principal default_princ;
198 
199  if (!principal.Length()) {
200  // Try the default user
201  if ((retval = krb5_parse_name(context, localUser.Data(),
202  &default_princ))) {
203  Error("Krb5Authenticate","failed <krb5_parse_name>: %s\n",
204  error_message(retval));
205  }
206  } else {
207  // Try first the name specified
208  if ((retval = krb5_parse_name(context, principal.Data(),
209  &default_princ))) {
210  TString errmsg = TString(Form("First: %s",error_message(retval)));
211  // Try the default user in case of failure
212  if ((retval = krb5_parse_name(context, localUser.Data(),
213  &default_princ))) {
214  errmsg.Append(Form("- Second: %s",error_message(retval)));
215  Error("Krb5Authenticate","failed <krb5_parse_name>: %s\n",
216  errmsg.Data());
217  }
218  }
219  }
220  //
221  // If successful, we get the string principal
222  if (!retval) {
223  char *default_name;
224  if ((retval = krb5_unparse_name(context, default_princ, &default_name))) {
225  Error("Krb5Authenticate","failed <krb5_unparse_name>: %s\n",
226  error_message(retval));
227  } else {
228  principal = TString(default_name);
229  free(default_name);
230  }
231  krb5_free_principal(context, default_princ);
232  }
233  }
234  // Notify
235  if (gDebug > 3) {
236  if (gotPrincipal)
237  Info("Krb5Authenticate",
238  "user requested principal: %s", principal.Data());
239  else
240  Info("Krb5Authenticate",
241  "default principal: %s", principal.Data());
242  }
243 
244  if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
245 
246  if (isatty(0) && isatty(1)) {
247 
248  if (gDebug > 1)
249  Info("Krb5Authenticate",
250  "valid credentials not found: try initializing (Principal: %s)",
251  principal.Data());
252  if (Krb5InitCred(principal, promptPrinc)) {
253  Error("Krb5Authenticate","error executing kinit");
254  return -1;
255  }
256  if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
257  Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
258  error_message(retval));
259  return -1;
260  }
261  } else {
262  Warning("Krb5Authenticate",
263  "not a tty: cannot prompt for credentials, returning failure");
264  return -1;
265  }
266  }
267 
268  // If a principal was specified by the user, we must check that the
269  // principal for which we have a cached ticket is the one that we want
270  TString ticketPrincipal =
271  TString(Form("%.*s@%.*s",client->data->length, client->data->data,
272  client->realm.length, client->realm.data));
273  if (gotPrincipal) {
274 
275  // If interactive require the ticket principal to be the same as the
276  // required or default one
277  if (isatty(0) && isatty(1) && principal != ticketPrincipal) {
278  if (gDebug > 3)
279  Info("Krb5Authenticate",
280  "got credentials for different principal %s - try"
281  " initialization credentials for principal: %s",
282  ticketPrincipal.Data(), principal.Data());
283  if (Krb5InitCred(principal)) {
284  Error("Krb5Authenticate","error executing kinit");
285  return -1;
286  }
287  if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
288  Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
289  error_message(retval));
290  return -1;
291  }
292  // This may have changed
293  ticketPrincipal =
294  TString(Form("%.*s@%.*s",client->data->length, client->data->data,
295  client->realm.length, client->realm.data));
296  }
297  }
298 
299  cleanup.fClient = client;
300 
301  TDatime expDate;
302  if (Krb5CheckCred(context, ccdef, ticketPrincipal, expDate) != 1) {
303 
304  // If the ticket expired we tray to re-initialize it for the same
305  // principal, which may be different from the default
306 
307  if (isatty(0) && isatty(1)) {
308 
309  if (gDebug >2)
310  Info("Krb5Authenticate",
311  "credentials found have expired: try initializing"
312  " (Principal: %s)", ticketPrincipal.Data());
313  if (Krb5InitCred(ticketPrincipal)) {
314  Error("Krb5Authenticate","error executing kinit");
315  return -1;
316  }
317  if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
318  Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
319  error_message(retval));
320  return -1;
321  }
322  // Check credentials and get expiration time
323  if (Krb5CheckCred(context, ccdef, ticketPrincipal, expDate) != 1) {
324  Info("Krb5Authenticate",
325  "ticket re-initialization failed for principal %s",
326  ticketPrincipal.Data());
327  return -1;
328  }
329  } else {
330  Warning("Krb5Authenticate",
331  "not a tty: cannot prompt for credentials, returning failure");
332  return -1;
333  }
334  }
335  cleanup.fClient = client;
336 
337  // At this point we know which is the principal we will be using
338  if (gDebug > 3)
339  Info("Krb5Authenticate",
340  "using valid ticket for principal: %s", ticketPrincipal.Data());
341 
342  // Get a normal string for user
343  TString normUser(client->data->data, client->data->length);
344 
345  if (gDebug > 3) {
346  Info("Krb5Authenticate", "cc_get_principal: client: %.*s %.*s",
347  client->data->length, client->data->data,
348  client->realm.length, client->realm.data);
349  }
350 
351  Int_t reuse = 1, prompt = 0;
352  TString details;
353 
354  if (version > 1) {
355 
356  // Check ReUse
357  reuse = TAuthenticate::GetAuthReUse();
358  prompt = TAuthenticate::GetPromptUser();
359 
360  // Build auth details
361  details = Form("pt:%d ru:%d us:%s", prompt, reuse, ticketPrincipal.Data());
362 
363  // Create Options string
364  int opt = reuse * kAUTH_REUSE_MSK +
365  auth->GetRSAKeyType() * kAUTH_RSATY_MSK;
366  TString options(Form("%d %d %s", opt, normUser.Length(), normUser.Data()));
367 
368  // Now we are ready to send a request to the rootd/proofd daemons
369  // to check if we have already a valid security context and
370  // eventually to start a negotiation to get one ...
371  kind = kROOTD_KRB5;
372  retval = reuse;
373  int rc = 0;
374  if ((rc = auth->AuthExists(ticketPrincipal, TAuthenticate::kKrb5,
375  options, &kind, &retval, &Krb5CheckSecCtx)) == 1) {
376  // A valid authentication exists: we are done ...
377  return 1;
378  }
379  if (rc == -2) {
380  return rc;
381  }
382 
383  if (kind == kROOTD_ERR) {
384  TString serv = "sockd";
385  if (strstr(auth->GetProtocol(),"root"))
386  serv = "rootd";
387  if (strstr(auth->GetProtocol(),"proof"))
388  serv = "proofd";
389  if (retval == kErrConnectionRefused) {
390  if (gDebug > 0)
391  Error("Krb5Authenticate",
392  "%s@%s does not accept connections from %s%s",
393  serv.Data(), auth->GetRemoteHost(),
394  auth->GetUser(), gSystem->HostName());
395  return -2;
396  } else if (retval == kErrNotAllowed) {
397  if (gDebug > 0)
398  Error("Krb5Authenticate",
399  "%s@%s does not accept %s authentication from %s@%s",
400  serv.Data(), auth->GetRemoteHost(),
402  auth->GetUser(), gSystem->HostName());
403  } else
404  TAuthenticate::AuthError("Krb5Authenticate", retval);
405  return 0;
406  }
407 
408  } else {
409 
410  nsen = sock->Send(kROOTD_KRB5);
411  if (nsen <= 0) {
412  Error("Krb5Authenticate","Sending kROOTD_KRB5");
413  return 0;
414  }
415  nrec = sock->Recv(retval, kind);
416  if (nrec <= 0) {
417  Error("Krb5Authenticate","Receiving kROOTD_KRB5");
418  return 0;
419  }
420 
421  // retval == 0 when no Krb5 support compiled in remote rootd
422  if (retval == 0 || kind != kROOTD_KRB5)
423  return 2;
424  }
425 
426  // ok, krb5 is supported
427  // ignore broken connection signal handling
429  cleanup.fSignal = kFALSE;
430 
431  // test for CRC-32
432  if (!krb5_c_valid_cksumtype(CKSUMTYPE_CRC32)) {
433  Error("Krb5Authenticate","failed <krb5_c_valid_cksumtype>: %s\n",
434  error_message(KRB5_PROG_SUMTYPE_NOSUPP));
435  return 0;
436  }
437 
438  // get service principal from service and host names --
439  // hard coding of service names avoids having the have these
440  // services in the local /etc/services file
441  TString service = TString("host");
442 
443  TString serv_host(sock->GetInetAddress().GetHostName());
444  krb5_principal server;
445 
446  if (gDebug > 3)
447  Info("Krb5Authenticate","serv_host: %s service: %s",
448  serv_host.Data(),service.Data());
449 
450  if ((retval = krb5_sname_to_principal(context, serv_host.Data(),
451  service.Data(), KRB5_NT_SRV_HST, &server))) {
452 
453  Error("Krb5Authenticate","failed <krb5_sname_to_principal>: %s\n",
454  error_message(retval));
455  return 0;
456  }
457  cleanup.fServer = server;
458 
459  if (gDebug > 3) {
460  Info("Krb5Authenticate","sname_to_principal: server: %.*s %.*s",
461  server->data->length, server->data->data,
462  server->realm.length, server->realm.data);
463  }
464 
465  // authenticate
466  krb5_auth_context auth_context = 0;
467  int sockd = sock->GetDescriptor();
468  char proto_version[100] = "krootd_v_1";
469  krb5_data cksum_data;
470  cksum_data.data = (char *)serv_host.Data(); // eeew yuck
471  cksum_data.length = serv_host.Length();
472  krb5_error *err_ret;
473  krb5_ap_rep_enc_part *rep_ret;
474 
475  retval = krb5_auth_con_init(context, &auth_context);
476  if (retval)
477  Error("Krb5Authenticate","failed auth_con_init: %s\n",
478  error_message(retval));
479  cleanup.fAuthContext = auth_context;
480 
481  retval = krb5_auth_con_setflags(context, auth_context,
482  KRB5_AUTH_CONTEXT_RET_TIME);
483  if (retval) Error("Krb5Authenticate","failed auth_con_setflags: %s\n",
484  error_message(retval));
485 
486  if (gDebug > 1)
487  Info("Krb5Authenticate",
488  "Sending kerberos authentication to %s",
489  serv_host.Data());
490 
491  retval = krb5_sendauth(context, &auth_context, (krb5_pointer)&sockd,
492  proto_version, client, server,
493  AP_OPTS_MUTUAL_REQUIRED,
494  &cksum_data,
495  0, // not rolling our own creds, using ccache
496  ccdef, &err_ret, &rep_ret, 0); // ugh!
497 
498  // handle the reply (this is a verbatim copy from the kerberos
499  // sample client source)
500  if (retval && retval != KRB5_SENDAUTH_REJECTED) {
501  Error("Krb5Authenticate","failed <krb5_sendauth>: %s\n",
502  error_message(retval));
503  return 0;
504  }
505  if (retval == KRB5_SENDAUTH_REJECTED) {
506  // got an error
507  Error("Krb5Authenticate", "sendauth rejected, error reply "
508  "is:\n\t\"%.*s\"",
509  err_ret->text.length, err_ret->text.data);
510  return 0;
511  } else if (!rep_ret) {
512  // no reply
513  return 0;
514  }
515  cleanup.fRepRet = rep_ret;
516 
517  if (version > 2) {
518 
519  // Send the targetUser name
520 
521  if (gDebug > 0)
522  Info("Krb5Authenticate","client is %s target is %s",
523  normUser.Data(),targetUser.Data());
524  nsen = sock->Send(targetUser.Data(), kROOTD_KRB5);
525  if (nsen <= 0) {
526  Error("Krb5Authenticate","Sending <targetUser>");
527  return 0;
528  }
529 
530  // If PROOF, send credentials
531  if (sock->GetServType() == TSocket::kPROOFD || version < 4) {
532 
533  krb5_data outdata;
534  outdata.data = 0;
535 
536  retval = krb5_auth_con_genaddrs(context, auth_context,
537  sockd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
538 
539  if (retval) {
540  Error("Krb5Authenticate","failed auth_con_genaddrs is: %s\n",
541  error_message(retval));
542  }
543 
544  retval = krb5_fwd_tgt_creds(context, auth_context, 0 /*host*/,
545  client, server, ccdef, true,
546  &outdata);
547  if (retval) {
548  Error("Krb5Authenticate","fwd_tgt_creds failed: %s\n",
549  error_message(retval));
550  return 0;
551  }
552 
553  cleanup.fData = outdata.data;
554 
555  if (gDebug > 3)
556  Info("Krb5Authenticate",
557  "Sending kerberos forward ticket to %s %p %d [%d,%d,%d,...]",
558  serv_host.Data(), outdata.data, outdata.length,
559  outdata.data[0], outdata.data[1], outdata.data[2]);
560 
561  // Send length first
562  char buflen[20];
563  snprintf(buflen, 20, "%d", outdata.length);
564  nsen = sock->Send(buflen, kROOTD_KRB5);
565  if (nsen <= 0) {
566  Error("Krb5Authenticate","Sending <buflen>");
567  return 0;
568  }
569 
570  // Send Key. second ...
571  nsen = sock->SendRaw(outdata.data, outdata.length);
572  if (nsen <= 0) {
573  Error("Krb5Authenticate","Sending <Key>");
574  return 0;
575  }
576 
577  if (gDebug>3)
578  Info("Krb5Authenticate",
579  "For kerberos forward ticket sent %d bytes (expected %d)",
580  nsen, outdata.length);
581  }
582  }
583 
584  // restore attention to broken connection signal handling
586 
587  // returns user@realm
588  type = kMESS_STRING;
589  nrec = sock->Recv(answer, 100, type);
590 
591  if (type == kROOTD_ERR) {
592  TAuthenticate::AuthError("Krb5Authenticate", kErrNoHome);
593  return 0;
594  }
595 
596  if (nrec <= 0) {
597  Error("Krb5Authenticate","Receiving <user@realm>");
598  return 0;
599  }
600  if (gDebug > 3)
601  Info("Krb5Auth","%s",answer);
602 
603  if (version > 1) {
604 
605  // Receive key request
606  nrec = sock->Recv(retval, type);
607  if (nrec <= 0) {
608  Error("Krb5Authenticate","Receiving <key request>");
609  return 0;
610  }
611 
612  Int_t rsaKey = 0;
613  if (reuse == 1) {
614 
615  if (type != kROOTD_RSAKEY || retval < 1 || retval > 2 ) {
616  Error("Krb5Auth",
617  "problems recvn RSA key flag: got message %d, flag: %d",
618  type, rsaKey);
619  return 0;
620  }
621  rsaKey = retval - 1;
622 
623  // Send the key securely
624  TAuthenticate::SendRSAPublicKey(sock, rsaKey);
625 
626  // get length of user + offset string
627  nrec = sock->Recv(retval, type);
628  if (nrec <= 0) {
629  Error("Krb5Authenticate","Receiving <length of user+offset string>");
630  return 0;
631  }
632  }
633 
634  if (type != kROOTD_KRB5 || retval < 1) {
635  Warning("Krb5Auth",
636  "problems recvn (user,offset) length (%d:%d bytes:%d)",
637  type, retval, nrec);
638  return 0;
639  }
640  char *rfrm = new char[retval+1];
641  nrec = sock->Recv(rfrm,retval+1, type); // receive user,offset) info
642  if (nrec <= 0) {
643  Error("Krb5Authenticate","Receiving <user+offset string>");
644  delete[] rfrm;
645  return 0;
646  }
647 
648  // Parse answer
649  char lUser[128];
650  int offset = -1;
651  sscanf(rfrm,"%127s %d", lUser, &offset);
652  // Save username
653  user = lUser;
654 
655  // Receive token
656  char *token = 0;
657  if (reuse == 1 && offset > -1) {
658  if (TAuthenticate::SecureRecv(sock, 1, rsaKey, &token) == -1) {
659  Warning("Krb5Auth",
660  "problems secure-receiving token - may result in corrupted token");
661  }
662  if (gDebug > 3)
663  Info("Krb5Auth","received from server: token: '%s' ", token);
664  } else {
665  token = StrDup("");
666  }
667 
668  // Create SecContext object
669  TRootSecContext *ctx =
670  auth->GetHostAuth()->CreateSecContext((const char *)lUser,
671  auth->GetRemoteHost(), (Int_t)TAuthenticate::kKrb5, offset,
672  details, token, expDate, 0, rsaKey);
673  // Transmit it to TAuthenticate
674  auth->SetSecContext(ctx);
675 
676  det = details;
677  if (token) delete[] token;
678  } else {
679  nrec = sock->Recv(answer, 100, type); // returns user
680  if (nrec <= 0) {
681  Error("Krb5Authenticate","Receiving <user string>");
682  return 0;
683  }
684  user = answer;
685 
686  // Get a SecContext for the record and avoid problems
687  // with fSecContext undefined in TAuthenticate
688  TRootSecContext *ctx =
689  auth->GetHostAuth()->CreateSecContext((const char *)user,
691  details, 0);
692  // Transmit it to TAuthenticate
693  auth->SetSecContext(ctx);
694  }
695 
696  // Receive auth from remote login function
697  int authok = 0;
698  nrec = sock->Recv(authok, kind);
699  if (nrec <= 0) {
700  Error("Krb5Authenticate", "Receiving <Auth flag>");
701  return 0;
702  }
703 
704  if (authok && kind == kROOTD_AUTH)
705  return 1;
706  return 0;
707 }
708 
709 ////////////////////////////////////////////////////////////////////////////////
710 /// Checks if there are valid credentials in the cache.
711 /// If not, tries to initialise them.
712 
713 Int_t Krb5InitCred(const char *clientPrincipal, Bool_t promptPrinc)
714 {
715  if (gDebug > 2)
716  Info("Krb5InitCred","enter: %s", clientPrincipal);
717 
718  // Check if the user wants to be prompt about principal
719  TString principal = TString(clientPrincipal);
720  if (TAuthenticate::GetPromptUser() || promptPrinc) {
721  const char *usr = Getline(Form("Principal (%s): ", principal.Data()));
722  if (usr[0]) {
723  TString usrs(usr);
724  usrs.Remove(usrs.Length() - 1); // get rid of \n
725  if (!usrs.IsNull())
726  principal = usrs;
727  }
728  }
729 
730  // Prepare command
731  TString cmd;
732 
733  if (strlen(R__KRB5INIT) <= 0)
734  cmd = Form("/usr/kerberos/bin/kinit -f %s", principal.Data());
735  else
736  cmd = Form("%s -f %s",R__KRB5INIT, principal.Data());
737 
738  if (gDebug > 2)
739  Info("Krb5InitCred","executing: %s", cmd.Data());
740  Int_t rc = gSystem->Exec(cmd);
741  if (rc)
742  if (gDebug > 0)
743  Info("Krb5InitCred", "error: return code: %d", rc);
744  return rc;
745 }
746 
747 ////////////////////////////////////////////////////////////////////////////////
748 /// Checks if there are valid credentials.
749 
750 Int_t Krb5CheckCred(krb5_context kCont, krb5_ccache Cc,
751  TString principal, TDatime &expDate)
752 {
753  Int_t retval;
754  Int_t now = time(0);
755  Int_t valid = -1;
756 
757  TString pdata = principal;
758  TString prealm = principal;
759  pdata.Resize(pdata.Index("@"));
760  prealm.Remove(0,prealm.Index("@")+1);
761  if (gDebug > 2)
762  Info("Krb5CheckCred","enter: principal '%s'", principal.Data());
763 
764  // Init to now
765  expDate = TDatime();
766 
767  krb5_cc_cursor cur;
768  if ((retval = krb5_cc_start_seq_get(kCont, Cc, &cur))) {
769  if (gDebug > 2)
770  Error("Krb5Authenticate","failed <krb5_cc_start_seq_get>: %s\n",
771  error_message(retval));
772  return 0;
773  }
774 
775  krb5_creds creds;
776  while (!(retval = krb5_cc_next_cred(kCont, Cc, &cur, &creds)) && valid == -1) {
777 
778  if (gDebug > 3) {
779  Info("Krb5CheckCred","creds.server->length: %d",
780  creds.server->length);
781  Info("Krb5CheckCred","Realms data: '%.*s' '%s'",
782  creds.server->realm.length, creds.server->realm.data,
783  prealm.Data());
784  Info("Krb5CheckCred","Srv data[0]: '%.*s' ",
785  creds.server->data[0].length, creds.server->data[0].data);
786  Info("Krb5CheckCred","Data data: '%.*s' '%s'",
787  creds.server->data[1].length, creds.server->data[1].data,
788  prealm.Data());
789  Info("Krb5CheckCred","Endtime: %d ", creds.times.endtime);
790  }
791 
792  if (creds.server->length == 2 &&
793  !strncmp(creds.server->realm.data,
794  prealm.Data(),creds.server->realm.length) &&
795  !strncmp((char *)creds.server->data[0].data,
796  "krbtgt",creds.server->data[0].length) &&
797  !strncmp((char *)creds.server->data[1].data,
798  prealm.Data(),creds.server->data[1].length)) {
799  // Check expiration time
800  valid = (creds.times.endtime >= now) ? 1 : 0;
801  // Return expiration time
802  expDate.Set(creds.times.endtime);
803  }
804  krb5_free_cred_contents(kCont, &creds);
805  }
806  return valid;
807 }
808 
809 ////////////////////////////////////////////////////////////////////////////////
810 /// Krb5 version of CheckSecCtx to be passed to TAuthenticate::AuthExists
811 /// Check if principal is matches the one used to instantiate Ctx
812 /// Returns: 1 if ok, 0 if not
813 /// Deactivates Ctx is not valid
814 
815 Int_t Krb5CheckSecCtx(const char *principal, TRootSecContext *ctx)
816 {
817  Int_t rc = 0;
818 
819  if (ctx->IsActive()) {
820  if (strstr(ctx->GetID(), principal))
821  rc = 1;
822  }
823  return rc;
824 }
Int_t Krb5Authenticate(TAuthenticate *, TString &, TString &, Int_t)
Kerberos v5 authentication code.
Definition: Krb5Auth.cxx:122
static void SetKrb5AuthHook(Krb5Auth_t func)
Set kerberos5 authorization function.
static Bool_t GetAuthReUse()
Static method returning the authentication reuse settings.
const char * GetHostName() const
Definition: TInetAddress.h:75
Int_t AuthExists(TString User, Int_t method, const char *Options, Int_t *Message, Int_t *Rflag, CheckSecCtx_t funcheck)
Check if we have a valid established sec context in memory Retrieves relevant info and negotiates wit...
const char * GetUser() const
Ssiz_t Length() const
Definition: TString.h:390
Int_t GetServType() const
Definition: TSocket.h:147
static TKrb5AuthInit gKrb5authInit
Definition: Krb5Auth.cxx:76
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition: TSocket.cxx:520
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition: TSocket.cxx:818
const char * GetRemoteHost() const
TSocket * GetSocket() const
Basic string class.
Definition: TString.h:137
Bool_t IsActive() const
Check remote OffSet and expiring Date.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
static Int_t Krb5CheckSecCtx(const char *, TRootSecContext *)
Krb5 version of CheckSecCtx to be passed to TAuthenticate::AuthExists Check if principal is matches t...
Definition: Krb5Auth.cxx:815
static const char * GetKrb5Principal()
Static method returning the principal to be used to init Krb5 tickets.
const Int_t kAUTH_RSATY_MSK
Definition: AuthConst.h:33
static Int_t Krb5InitCred(const char *clientPrincipal, Bool_t promptPrinc=kFALSE)
Checks if there are valid credentials in the cache.
Definition: Krb5Auth.cxx:713
virtual Int_t GetDescriptor() const
Definition: TSocket.h:142
const char * Data() const
Definition: TString.h:349
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:620
const char * GetProtocol() const
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1627
void Info(const char *location, const char *msgfmt,...)
TString & Append(const char *cs)
Definition: TString.h:492
virtual UserGroup_t * GetUserInfo(Int_t uid)
Returns all user info in the UserGroup_t structure.
Definition: TSystem.cxx:1563
static Bool_t GetPromptUser()
Static method returning the prompt user settings.
void Error(const char *location, const char *msgfmt,...)
const Int_t kAUTH_REUSE_MSK
Definition: AuthConst.h:30
void SetSecContext(TRootSecContext *ctx)
static void AuthError(const char *where, Int_t error)
Print error string depending on error code.
TString fUser
Definition: TSystem.h:152
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
Int_t GetRSAKeyType() const
char * Form(const char *fmt,...)
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition: TSystem.cxx:658
THostAuth * GetHostAuth() const
Bool_t IsNull() const
Definition: TString.h:387
void Warning(const char *location, const char *msgfmt,...)
static const char * GetDefaultUser()
Static method returning the default user information.
static Int_t Krb5CheckCred(krb5_context, krb5_ccache, TString, TDatime &)
Checks if there are valid credentials.
Definition: Krb5Auth.cxx:750
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2514
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
TRootSecContext * CreateSecContext(const char *user, const char *host, Int_t meth, Int_t offset, const char *details, const char *token, TDatime expdate=kROOTTZERO, void *ctx=0, Int_t key=-1)
Create a Security context and add it to local list Return pointer to it to be stored in TAuthenticate...
Definition: THostAuth.cxx:725
virtual const char * HostName()
Return the system&#39;s host name.
Definition: TSystem.cxx:308
int type
Definition: TGX11.cxx:120
#define free
Definition: civetweb.c:821
static Int_t SecureRecv(TSocket *Socket, Int_t dec, Int_t KeyType, char **Out)
Receive str from sock and decode it using key indicated by key type Return number of received bytes o...
const char * GetID() const
Definition: TSecContext.h:82
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
#define snprintf
Definition: civetweb.c:822
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
TInetAddress GetInetAddress() const
Definition: TSocket.h:143
const Bool_t kTRUE
Definition: Rtypes.h:91
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1059
static Int_t SendRSAPublicKey(TSocket *Socket, Int_t key=0)
Receives server RSA Public key Sends local RSA public key encoded.
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:39
static const char * GetAuthMethod(Int_t idx)
Static method returning the method corresponding to idx.
virtual void IgnoreSignal(ESignals sig, Bool_t ignore=kTRUE)
If ignore is true ignore the specified signal, else restore previous behaviour.
Definition: TSystem.cxx:598