#include<afscred.h>
#include<dynimport.h>
#include<krb5common.h>
+#include<winsock2.h>
+#include<afs/cm.h>
#pragma warning (pop)
+static char *afs_realm_of_cell(afs_conf_cell *, BOOL);
+static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short ipRank);
+static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
+
BOOL
afs_is_running(void) {
DWORD CurrentState;
}
+static void
+copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
+ krb5_error_code code;
+ krb5_ticket *ticket;
+ size_t len;
+
+ code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
+ if (code == 0) {
+ len = krb5_princ_realm(context, ticket->server)->length;
+ if (len > destlen - 1)
+ len = destlen - 1;
+
+ StringCbCopyA(dest, len, krb5_princ_realm(context, ticket->server)->data);
+
+ pkrb5_free_ticket(context, ticket);
+ }
+}
+
int
afs_klog(khm_handle identity,
char *service,
char *realm,
int LifeTime,
afs_tk_method method,
- time_t * tok_expiration) {
+ time_t * tok_expiration,
+ char *linkedCell) {
long rc;
CREDENTIALS creds;
struct ktc_principal aserver;
struct ktc_principal aclient;
- char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
- char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
+ char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
+ char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
char local_cell[MAXCELLCHARS+1];
char Dmycell[MAXCELLCHARS+1];
struct ktc_token atoken;
if ( !cell ) cell = "";
if ( !service ) service = "";
+ memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
memset(RealmName, '\0', sizeof(RealmName));
memset(CellName, '\0', sizeof(CellName));
memset(ServiceName, '\0', sizeof(ServiceName));
return(rc);
}
+ if (linkedCell && ak_cellconfig.linkedCell)
+ StringCbCopyA(linkedCell, MAXCELLCHARS,
+ ak_cellconfig.linkedCell);
+
StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
afs_realm_of_cell(&ak_cellconfig, FALSE));
pkrb5_cc_get_principal(context, k5cc, &client_principal);
i = krb5_princ_realm(context, client_principal)->length;
- if (i > REALM_SZ-1)
- i = REALM_SZ-1;
+ if (i > MAXKTCREALMLEN-1)
+ i = MAXKTCREALMLEN-1;
StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
krb5_princ_realm(context, client_principal)->data,
i);
goto try_krb4;
}
- /* First try Service/Cell@REALM */
- if (r = pkrb5_build_principal(context, &increds.server,
- (int) strlen(RealmName),
- RealmName,
- ServiceName,
- CellName,
- 0)) {
- _reportf(L"krb5_build_principal returns %d", r);
- goto end_krb5;
- }
-
increds.client = client_principal;
increds.times.endtime = 0;
/* Ask for DES since that is what V4 understands */
flags = KRB5_TC_OPENCLOSE;
r = pkrb5_cc_set_flags(context, k5cc, flags);
#endif
- retry_retcred:
- r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
- if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
- r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
- !RealmName[0]) {
- StringCbCopyA(RealmName, sizeof(RealmName),
- afs_realm_of_cell(&ak_cellconfig, TRUE));
-
- pkrb5_free_principal(context, increds.server);
- r = pkrb5_build_principal(context, &increds.server,
- (int) strlen(RealmName),
- RealmName,
- ServiceName,
- CellName,
- 0);
- if (r == 0)
- r = pkrb5_get_credentials(context, 0, k5cc,
- &increds, &k5creds);
- }
- if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
- r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
- /* Next try Service@REALM */
- pkrb5_free_principal(context, increds.server);
- r = pkrb5_build_principal(context, &increds.server,
- (int) strlen(RealmName),
- RealmName,
- ServiceName,
- 0);
- if (r == 0)
- r = pkrb5_get_credentials(context, 0, k5cc,
- &increds, &k5creds);
- }
+ if (strlen(realm) != 0) {
+ retry_retcred_1:
+ /* First try Service/Cell@REALM */
+ if (r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm),
+ realm,
+ ServiceName,
+ CellName,
+ 0)) {
+ _reportf(L"krb5_build_principal returns %d", r);
+ goto end_krb5;
+ }
- /* Check to make sure we received a valid ticket; if not remove it
- * and try again. Perhaps there are two service tickets for the
- * same service in the ccache.
- */
- if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
- pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
- pkrb5_free_creds(context, k5creds);
- k5creds = NULL;
- goto retry_retcred;
- }
+ r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
+ if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+ r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+ r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+ /* Next try Service@REALM */
+ pkrb5_free_principal(context, increds.server);
+ r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm),
+ realm,
+ ServiceName,
+ 0);
+ if (r == 0)
+ r = pkrb5_get_credentials(context, 0, k5cc,
+ &increds, &k5creds);
+ }
+
+ /* Check to make sure we received a valid ticket; if not remove it
+ * and try again. Perhaps there are two service tickets for the
+ * same service in the ccache.
+ */
+ if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
+ pkrb5_free_principal(context, increds.server);
+ pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
+ pkrb5_free_creds(context, k5creds);
+ k5creds = NULL;
+ goto retry_retcred_1;
+ }
+ } else {
+ retry_retcred_2:
+ /* First try Service/Cell@_CLIENT_REALM */
+ if (r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm_of_user),
+ realm_of_user,
+ ServiceName,
+ CellName,
+ 0)) {
+ _reportf(L"krb5_build_principal returns %d", r);
+ goto end_krb5;
+ }
+
+ r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
+ if (r == 0) {
+ /* the user realm is a valid cell realm */
+ StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
+ }
+ if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+ r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+ r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+ pkrb5_free_principal(context, increds.server);
+ r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm_of_cell),
+ realm_of_cell,
+ ServiceName,
+ CellName,
+ 0);
+ if (r == 0)
+ r = pkrb5_get_credentials(context, 0, k5cc,
+ &increds, &k5creds);
+ }
+ if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+ r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+ r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
+ strlen(realm_of_cell) == 0) {
+ StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
+ afs_realm_of_cell(&ak_cellconfig, TRUE));
+
+ pkrb5_free_principal(context, increds.server);
+ r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm_of_cell),
+ realm_of_cell,
+ ServiceName,
+ CellName,
+ 0);
+ if (r == 0)
+ r = pkrb5_get_credentials(context, 0, k5cc,
+ &increds, &k5creds);
+ }
+ if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+ r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+ r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+ /* Next try Service@REALM */
+ StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
+ afs_realm_of_cell(&ak_cellconfig, FALSE));
+
+ pkrb5_free_principal(context, increds.server);
+ r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm_of_cell),
+ realm_of_cell,
+ ServiceName,
+ 0);
+ if (r == 0)
+ r = pkrb5_get_credentials(context, 0, k5cc,
+ &increds, &k5creds);
+ }
+ if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+ r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+ r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
+ strlen(realm_of_cell) == 0) {
+ /* Next try Service@REALM */
+ StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
+ afs_realm_of_cell(&ak_cellconfig, TRUE));
+
+ pkrb5_free_principal(context, increds.server);
+ r = pkrb5_build_principal(context, &increds.server,
+ (int) strlen(realm_of_cell),
+ realm_of_cell,
+ ServiceName,
+ 0);
+ if (r == 0)
+ r = pkrb5_get_credentials(context, 0, k5cc,
+ &increds, &k5creds);
+ }
+
+ if (r == 0 && strlen(realm_of_cell) == 0)
+ copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
+
+ /* Check to make sure we received a valid ticket; if not remove it
+ * and try again. Perhaps there are two service tickets for the
+ * same service in the ccache.
+ */
+ if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
+ pkrb5_free_principal(context, increds.server);
+ pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
+ pkrb5_free_creds(context, k5creds);
+ k5creds = NULL;
+ goto retry_retcred_2;
+ }
+ }
pkrb5_free_principal(context, increds.server);
pkrb5_free_principal(context, client_principal);
_reportf(L"Same token already exists");
- return 0;
+ rc = 0;
+ goto cleanup;
}
// * Reset the "aclient" structure before we call ktc_SetToken.
if (context)
pkrb5_free_context(context);
- return 0;
+ goto cleanup;
}
_reportf(L"SetToken returns code %d", rc);
_reportf(L"Kerberos 4 not configured");
if (!bGotCreds && supports_krb4 &&
+ strlen(RealmName) < REALM_SZ &&
(method == AFS_TOKEN_AUTO ||
method == AFS_TOKEN_KRB4)) {
!memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
/* success! */
- return(0);
+ rc = 0;
+ goto cleanup;
}
// Reset the "aclient" structure before we call ktc_SetToken.
if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
afs_report_error(rc, "ktc_SetToken()");
- return(rc);
+ goto cleanup;
}
} else if (method == AFS_TOKEN_AUTO ||
method >= AFS_TOKEN_USER) {
}
}
+ cleanup:
+ if (ak_cellconfig.linkedCell)
+ free(ak_cellconfig.linkedCell);
+
return rc;
}
afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
{
char krbhst[MAX_HSTNM]="";
- static char krbrlm[REALM_SZ+1]="";
+ static char krbrlm[MAXKTCREALMLEN+1]="";
krb5_context ctx = 0;
char ** realmlist=NULL;
krb5_error_code r = 0;
afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
{
int rc;
- int ttl;
+ int ttl = 0;
+ char linkedCell[MAXCELLCHARS]="";
local_cell[0] = (char)0;
memset(cellconfig, 0, sizeof(*cellconfig));
if (strlen(cell) == 0)
StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
- /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
- rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
- (void*)cellconfig);
+ rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
+ afs_get_cellconfig_callback, (void*) cellconfig);
+ if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
+ rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
+ (void*)cellconfig);
if(rc)
rc = cm_SearchCellByDNS(cell, NULL, &ttl,
afs_get_cellconfig_callback,
(void*) cellconfig);
+ if (linkedCell[0])
+ cellconfig->linkedCell = _strdup(linkedCell);
+
return rc;
}
static long
afs_get_cellconfig_callback(void *cellconfig,
struct sockaddr_in *addrp,
- char *namep)
+ char *namep,
+ unsigned short ipRank)
{
afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
int rc;
ZeroMemory(local_cell, sizeof(local_cell));
+ ZeroMemory(&cellconfig, sizeof(cellconfig));
rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
if (rc)
return FALSE;
realm = afs_realm_of_cell(&cellconfig, FALSE);
- if (realm == NULL)
- return FALSE;
+ if (cellconfig.linkedCell)
+ free(cellconfig.linkedCell);
+ if (!realm[0]) /* referral; assume it matches */
+ return TRUE;
AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);