/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * krbtgt.c * * Abstract: * * Likewise Advanced API (lwadvapi) * * Kerberos 5 runtime environment * * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com) * Sriram Nambakam (snambakam@likewisesoftware.com) * Rafal Szczesniak * */ #include "includes.h" #include "krbtgt_p.h" DWORD LwKrb5GetTgt( PCSTR pszUserPrincipal, PCSTR pszPassword, PCSTR pszCcPath, PDWORD pdwGoodUntilTime ) { DWORD dwError = LW_ERROR_SUCCESS; krb5_error_code ret = 0; krb5_context ctx = NULL; krb5_ccache cc = NULL; krb5_get_init_creds_opt opts; krb5_principal client = NULL; krb5_creds creds = {0}; PSTR pszPass = NULL; PSTR pszUPN = NULL; PSTR pszRealmIdx = NULL; BOOLEAN bUnlockExistingClientLock = FALSE; dwError = LwAllocateString( pszUserPrincipal, &pszUPN); BAIL_ON_LW_ERROR(dwError); if ((pszRealmIdx = strchr(pszUPN, '@')) == NULL) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LW_ERROR(dwError); } LwStrToUpper(++pszRealmIdx); ret = krb5_init_context(&ctx); BAIL_ON_KRB_ERROR(ctx, ret); krb5_get_init_creds_opt_init(&opts); krb5_get_init_creds_opt_set_tkt_life(&opts, LW_KRB5_DEFAULT_TKT_LIFE); krb5_get_init_creds_opt_set_forwardable(&opts, TRUE); if (LW_IS_NULL_OR_EMPTY_STR(pszCcPath)) { ret = krb5_cc_default(ctx, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } else { ret = krb5_cc_resolve(ctx, pszCcPath, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } ret = krb5_parse_name(ctx, pszUPN, &client); BAIL_ON_KRB_ERROR(ctx, ret); if (!LW_IS_NULL_OR_EMPTY_STR(pszPassword)) { dwError = LwAllocateString(pszPassword, &pszPass); BAIL_ON_LW_ERROR(dwError); } ret = krb5_get_init_creds_password(ctx, &creds, client, pszPass, NULL, NULL, 0, NULL, &opts); BAIL_ON_KRB_ERROR(ctx, ret); if (ret == KRB5KRB_AP_ERR_SKEW) { ret = krb5_get_init_creds_password(ctx, &creds, client, pszPass, NULL, NULL, 0, NULL, &opts); BAIL_ON_KRB_ERROR(ctx, ret); } else { BAIL_ON_KRB_ERROR(ctx, ret); } dwError = pthread_mutex_lock(&gLwKrb5State.ExistingClientLock); BAIL_ON_LW_ERROR(dwError); bUnlockExistingClientLock = TRUE; /* Blow away the old credentials cache so that the old TGT is removed. * Otherwise, the new TGT will be stored at the end of the credentials * cache, and kerberos will use the old TGT instead. * * See bug 6908. */ ret = krb5_cc_initialize(ctx, cc, client); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_cc_store_cred(ctx, cc, &creds); BAIL_ON_KRB_ERROR(ctx, ret); if (pdwGoodUntilTime) { *pdwGoodUntilTime = creds.times.endtime; } cleanup: if (bUnlockExistingClientLock) { pthread_mutex_unlock(&gLwKrb5State.ExistingClientLock); } if (ctx) { if (client) { krb5_free_principal(ctx, client); } krb5_cc_close(ctx, cc); krb5_free_cred_contents(ctx, &creds); krb5_free_context(ctx); } LW_SAFE_FREE_STRING(pszUPN); LW_SAFE_CLEAR_FREE_STRING(pszPass); return dwError; error: if (pdwGoodUntilTime) { *pdwGoodUntilTime = 0; } goto cleanup; } DWORD LwKrb5GetTgs( PCSTR pszCliPrincipal, PCSTR pszSvcPrincipal, PSTR pszCcPath ) { DWORD dwError = LW_ERROR_SUCCESS; krb5_error_code ret = 0; krb5_context ctx = NULL; krb5_ccache cc = NULL; krb5_flags opts = 0; krb5_principal client = NULL; krb5_principal service = NULL; krb5_creds tgs_req = {0}; krb5_creds* tgs_rep = NULL; ret = krb5_init_context(&ctx); BAIL_ON_KRB_ERROR(ctx, ret); if (LW_IS_NULL_OR_EMPTY_STR(pszCcPath)) { ret = krb5_cc_default(ctx, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } else { ret = krb5_cc_resolve(ctx, pszCcPath, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } ret = krb5_parse_name(ctx, pszCliPrincipal, &client); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_parse_name(ctx, pszSvcPrincipal, &service); BAIL_ON_KRB_ERROR(ctx, ret); tgs_req.client = client; tgs_req.server = service; tgs_req.times.endtime = time(NULL) + LW_KRB5_DEFAULT_TKT_LIFE; ret = krb5_get_credentials(ctx, opts, cc, &tgs_req, &tgs_rep); BAIL_ON_KRB_ERROR(ctx, ret); cleanup: if (ctx) { if (client) { krb5_free_principal(ctx, client); } if (service) { krb5_free_principal(ctx, service); } if (tgs_rep) { krb5_free_creds(ctx, tgs_rep); } if (cc) { krb5_cc_close(ctx, cc); } krb5_free_context(ctx); } return dwError; error: goto cleanup; } DWORD LwKrb5GetServiceTicketForUser( uid_t uid, PCSTR pszUserPrincipal, PCSTR pszServername, PCSTR pszDomain, Krb5CacheType cacheType ) { DWORD dwError = 0; krb5_error_code ret = 0; krb5_context ctx = NULL; krb5_ccache cc = NULL; krb5_creds in_creds = {0}; krb5_creds* pCreds = NULL; krb5_principal user_principal = NULL; krb5_principal server_principal = NULL; PSTR pszCachePath = NULL; PSTR pszTargetName = NULL; PSTR pszUPN = NULL; PSTR pszRealmIdx = NULL; LW_BAIL_ON_INVALID_STRING(pszUserPrincipal); LW_BAIL_ON_INVALID_STRING(pszServername); dwError = LwAllocateString( pszUserPrincipal, &pszUPN); BAIL_ON_LW_ERROR(dwError); if ((pszRealmIdx = strchr(pszUPN, '@')) == NULL) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LW_ERROR(dwError); } LwStrToUpper(++pszRealmIdx); ret = krb5_init_context(&ctx); BAIL_ON_KRB_ERROR(ctx, ret); dwError = LwKrb5GetUserCachePath( uid, cacheType, &pszCachePath); BAIL_ON_LW_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pszCachePath)) { ret = krb5_cc_default(ctx, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } else { ret = krb5_cc_resolve(ctx, pszCachePath, &cc); BAIL_ON_KRB_ERROR(ctx, ret); } ret = krb5_parse_name(ctx, pszUPN, &user_principal); BAIL_ON_KRB_ERROR(ctx, ret); dwError = LwAllocateStringPrintf( &pszTargetName, "%s$@%s", pszServername, pszDomain); BAIL_ON_LW_ERROR(dwError); LwStrToUpper(pszTargetName); ret = krb5_parse_name(ctx, pszTargetName, &server_principal); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_copy_principal(ctx, user_principal, &in_creds.client); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_copy_principal(ctx, server_principal, &in_creds.server); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_get_credentials( ctx, 0, cc, &in_creds, &pCreds); BAIL_ON_KRB_ERROR(ctx, ret); cleanup: if (ctx) { if (user_principal) { krb5_free_principal(ctx, user_principal); } if (server_principal) { krb5_free_principal(ctx, server_principal); } if (cc) { krb5_cc_close(ctx, cc); } krb5_free_cred_contents(ctx, &in_creds); if (pCreds) { krb5_free_creds(ctx, pCreds); } krb5_free_context(ctx); } LW_SAFE_FREE_STRING(pszCachePath); LW_SAFE_FREE_STRING(pszTargetName); LW_SAFE_FREE_STRING(pszUPN); return dwError; error: goto cleanup; } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */