krb5_child.c revision 19e44537c28f6d5f011cd7ac885c74c1e892605f
/*
SSSD
Kerberos 5 Backend Module -- tgt_req and changepw child
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2009-2010 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <popt.h>
#include <security/pam_modules.h>
#include "util/sss_krb5.h"
#include "util/user_info_msg.h"
#include "util/child_common.h"
#include "util/find_uid.h"
#include "src/util/util_errors.h"
#include "providers/dp_backend.h"
#include "providers/krb5/krb5_auth.h"
#include "providers/krb5/krb5_utils.h"
#include "sss_cli.h"
#define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
enum k5c_fast_opt {
};
struct krb5_req {
char* name;
bool otp;
char *otp_vendor;
char *otp_token_id;
char *otp_challenge;
char *realm;
char *ccname;
char *keytab;
bool validate;
bool send_pac;
bool use_enterprise_princ;
char *fast_ccname;
const char *upn;
char *old_ccname;
bool old_cc_valid;
bool old_cc_active;
enum k5c_fast_opt fast_val;
};
static krb5_context krb5_error_ctx;
{
char *lifetime_str;
if (lifetime_str == NULL) {
/* Unset option flag to make sure defaults from krb5.conf are used. */
} else {
if (kerr != 0) {
"krb5_string_to_deltat failed for [%s].\n",
return kerr;
}
}
if (lifetime_str == NULL) {
/* Unset option flag to make sure defaults from krb5.conf are used. */
} else {
if (kerr != 0) {
"krb5_string_to_deltat failed for [%s].\n",
return kerr;
}
}
return 0;
}
{
int canonicalize = 0;
char *tmp_str;
canonicalize = 1;
}
}
{
}
{
/* Currently we do not set forwardable and proxiable explicitly, the flags
* must be removed so that libkrb5 can take the defaults from krb5.conf */
if (kerr != 0) {
}
}
{
struct sss_cli_req_data sss_data;
int ret;
int errnop;
return EIO;
}
"PAC responder contacted. It might take a bit of time in case the "
"cache is not up to date.\n");
return EOK;
}
{
int ret;
long exp_time;
if (password_expiration == 0) {
return;
}
return;
}
return;
}
}
return;
}
/*
* TODO: These features generally would requires a significant refactoring
* of SSSD and MIT krb5 doesn't support them anyway. They are listed here
* simply as a reminder of things that might become future feature potential.
*
* 1. tokeninfo selection
* 2. challenge
* 4. interactive otp format correction
* 5. nextOTP
*
*/
typedef int (*checker)(int c);
{
switch (format) {
return isdigit;
return isxdigit;
return isalnum;
}
return NULL;
}
static int token_pin_destructor(char *mem)
{
return 0;
}
const krb5_responder_otp_tokeninfo *ti,
{
int i;
return ENOTSUP;
}
return ENOTSUP;
}
/* This is a non-sensical value. */
return EPROTO;
}
"Expected [%d] and given [%zu] token size "
return EMSGSIZE;
}
return ENOMEM;
}
return ENOMEM;
}
}
} else {
return ENOMEM;
}
}
} else {
/* Assuming PIN only required */
return ENOMEM;
}
}
/* If check is set, we need to verify the contents of the token. */
return EBADMSG;
}
}
return 0;
}
const krb5_responder_otp_tokeninfo *ti,
{
int i;
return ENOTSUP;
}
return ENOTSUP;
}
/* This is a non-sensical value. */
return EPROTO;
}
/* ASSUMPTION: authtok has one of the following formats:
* 1. TokenValue
* 2. PIN+TokenValue
*/
return ENOMEM;
}
/* If the server desires a separate pin, we will split it.
* ASSUMPTION: Format of authtok is PIN+TokenValue. */
return ENOTSUP;
}
return EMSGSIZE;
}
/* Copy the PIN from the front of the value. */
return ENOMEM;
}
/* Remove the PIN from the front of the token value. */
} else {
return EMSGSIZE;
}
}
} else {
return EMSGSIZE;
}
}
} else {
return ENOMEM;
}
}
/* If check is set, we need to verify the contents of the token. */
return EBADMSG;
}
}
return 0;
}
const krb5_responder_otp_tokeninfo *ti,
struct sss_auth_token *auth_tok,
{
int ret;
const char *pwd;
const char *fa2;
switch (sss_authtok_get_type(auth_tok)) {
return ret;
}
break;
case SSS_AUTHTOK_TYPE_2FA:
return ret;
}
break;
default:
}
return EINVAL;
}
{
size_t i;
/* Either an error, or nothing to do. */
return ret;
}
/* No tokeninfos? Absurd! */
goto done;
}
}
}
}
}
/* Allocation errors are ignored on purpose */
return EAGAIN;
}
/* Find the first supported tokeninfo which matches our authtoken. */
break;
}
switch (ret) {
case EBADMSG:
case EMSGSIZE:
case ENOTSUP:
case EPROTO:
break;
default:
goto done;
}
}
"No tokeninfos found which match our credentials.\n");
goto done;
}
/* Don't let SSSD cache the OTP authtok since it is single-use. */
goto done;
}
}
/* Respond with the appropriate answer. */
done:
return ret;
}
void *data,
{
return EINVAL;
}
}
#endif
{
int ret;
if (num_prompts != 0) {
return KRB5_LIBOS_CANTREADPWD;
}
"Prompter called with empty banner, nothing to do.\n");
return EOK;
}
}
return EOK;
}
krb5_creds **_cred)
{
return ENOMEM;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
done:
if (kerr != 0) {
} else {
}
return kerr;
}
{
int ret;
/* We only treat the FILE type case in a special way due to the history
* of storing FILE type ccache in /tmp and associated security issues */
if (in[0] == '/') {
} else {
return EOK;
}
/* NOTE: this call is only used to create a unique name, as later
* krb5_cc_initialize() will unlink and recreate the file.
* This is ok because this part of the code is called with
* privileges already dropped when handling user ccache, or the ccache
* is stored in a private directory. So we do not have huge issues if
* something races, we mostly care only about not accidentally use
* an existing name and thus failing in the process of saving the
* cache. Malicious races can only be avoided by libkrb5 itself. */
"mkstemp(\"%s\") failed [%d]: %s!\n",
return ret;
}
}
return EOK;
}
/* NOTE: callers rely on 'name' being *changed* if it needs to be randomized,
* as they will then send the name back to the new name via the return call
* k5c_attach_ccname_msg(). Callers will send in a copy of the name if they
* do not care for changes. */
{
const char *type;
#ifdef HAVE_KRB5_CC_COLLECTION
bool switch_to_cc = false;
#endif
/* Set a restrictive umask, just in case we end up creating any file */
/* we create a new context here as the main process one may have been
* opened as root and contain possibly references (even open handles ?)
* to resources we do not have or do not want to have access to */
if (kerr) {
return ERR_INTERNAL;
}
if (kerr) {
goto done;
}
if (kerr) {
goto done;
}
#ifdef HAVE_KRB5_CC_COLLECTION
if (kerr) {
goto done;
}
if (kerr == KRB5_CC_NOTFOUND) {
switch_to_cc = true;
}
if (kerr) {
goto done;
}
}
#endif
if (kerr) {
goto done;
}
if (kerr) {
goto done;
}
#ifdef HAVE_KRB5_CC_COLLECTION
if (switch_to_cc) {
if (kerr) {
goto done;
}
}
#endif
done:
if (kcc) {
/* FIXME: should we krb5_cc_destroy in case of error ? */
}
return kerr;
}
struct response_data *resp_list,
{
size_t p = 0;
struct response_data *pdr;
/* A buffer with the following structure must be created:
* int32_t status of the request (required)
* message (zero or more)
*
* A message consists of:
* int32_t type of the message
* int32_t length of the following data
* uint8_t[len] data
*/
}
if (!buf) {
return ENOMEM;
}
}
*_len = p;
return EOK;
}
{
int ret;
size_t vendor_len = 0;
size_t token_id_len = 0;
size_t challenge_len = 0;
msg_len = 3;
msg_len += vendor_len;
}
msg_len += token_id_len;
}
msg_len += challenge_len;
}
return ENOMEM;
}
}
}
}
return ret;
}
{
int ret;
return ERR_INTERNAL;
}
return ENOMEM;
}
return ret;
}
{
int ret;
return ret;
}
errno = 0;
if (written == -1) {
return ret;
}
"Write error, wrote [%zu] bytes, expected [%zu]\n",
return EOK;
}
return EOK;
}
{
int ret;
int64_t t[4];
unsigned int upn_len = 0;
goto done;
}
if (kerr != 0) {
goto done;
}
goto done;
}
done:
return ret;
}
{
bool realm_entry_found = false;
if (kerr != 0) {
return kerr;
}
if (kerr != 0) {
return kerr;
}
/* We look for the first entry from our realm or take the last one */
if (validation_princ != NULL) {
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
}
"Found keytab entry with the realm of the credential.\n");
realm_entry_found = true;
break;
}
}
if (!realm_entry_found) {
"Keytab entry with the realm of the credential not found "
"in keytab. Using the last entry.\n");
}
/* Close the keytab here. Even though we're using cursors, the file
* handle is stored in the krb5_keytab structure, and it gets
* overwritten when the verify_init_creds() call below creates its own
* cursor, creating a leak. */
if (kerr != 0) {
"not verifying TGT.\n");
goto done;
}
/* check if we got any errors from krb5_kt_next_entry */
goto done;
}
/* Get the principal to which the key belongs, for logging purposes. */
if (kerr != 0) {
"not verifying TGT.\n");
goto done;
}
&validation_ccache, &opt);
if (kerr == 0) {
} else {
"for [%s].\n", principal);
goto done;
}
/* Try to find and send the PAC to the PAC responder.
* Failures are not critical. */
if (kerr != 0) {
"membership for user with principal [%s] " \
kerr = 0;
goto done;
}
if (kerr != 0) {
"membership for user with principal [%s] " \
kerr = 0;
}
}
done:
if (validation_ccache != NULL) {
}
}
if (validation_princ != NULL) {
}
}
return kerr;
}
char *ccname)
{
krb5_error_code kerr = 0;
&options);
if (kerr != 0) {
return kerr;
}
/* Use the updated principal in the creds in case canonicalized */
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
return kerr;
}
const char *password)
{
const char *realm_name;
int realm_length;
char *cc_name;
kr);
if (kerr != 0) {
"Failed to set expire callback, continue without.\n");
}
if (realm_length == 0) {
return KRB5KRB_ERR_GENERIC;
}
"Attempting kinit for realm [%s]\n",realm_name);
sss_krb5_prompter, kr, 0,
/* Any errors are ignored during pre-auth, only data is collected to
* be send back to the client.*/
"krb5_get_init_creds_password returned [%d} during pre-auth.\n",
kerr);
return 0;
} else {
if (kerr != 0) {
return kerr;
}
}
if (kerr != 0) {
return kerr;
}
} else {
}
/* If kr->ccname is cache collection (DIR:/...), we want to work
* directly with file ccache (DIR::/...), but cache collection
* should be returned back to back end.
*/
}
/* Use the updated principal in the creds in case canonicalized */
if (kerr != 0) {
goto done;
}
/* Successfull authentication! Check if ccache contains the
* right principal...
*/
if (kerr) {
goto done;
}
"Failed to remove old ccache file [%s], "
}
if (kerr != 0) {
"add_ticket_times_and_upn_to_response failed.\n");
}
kerr = 0;
done:
return kerr;
}
{
if (kerr != 0) {
}
switch (kerr) {
case 0:
return ERR_OK;
case KRB5_LIBOS_CANTREADPWD:
return ERR_NO_CREDS;
case KRB5_KDCREP_SKEW:
case KRB5KRB_AP_ERR_SKEW:
case KRB5_KDC_UNREACH:
case KRB5_REALM_CANT_RESOLVE:
case KRB5_REALM_UNKNOWN:
return ERR_NETWORK_IO;
return ERR_ACCOUNT_LOCKED;
case KRB5KDC_ERR_NAME_EXP:
return ERR_ACCOUNT_EXPIRED;
case KRB5KDC_ERR_KEY_EXP:
return ERR_CREDS_EXPIRED;
return ERR_AUTH_FAILED;
/* ERR_CREDS_INVALID is used to indicate to the IPA provider that trying
* password migration would make sense. All Kerberos error codes which can
* be seen while migrating LDAP users to IPA should be added here. */
case KRB5_PROG_ETYPE_NOSUPP:
case KRB5_PREAUTH_FAILED:
return ERR_CREDS_INVALID;
/* Please do not remove KRB5KRB_ERR_GENERIC here, it is a _generic_ error
* code and we cannot make any assumptions about the reason for the error.
* As a consequence we cannot return a different error code than a generic
* one which unfortunately might result in a unspecific system error
* message to the user.
*
* If there are cases where libkrb5 calls return KRB5KRB_ERR_GENERIC where
* SSSD should behave differently this has to be detected by different
* means, e.g. by evaluation error messages, and then the error code
* should be changed to a more suitable KRB5* error code or immediately to
* a SSSD ERR_* error code to avoid the default handling here. */
case KRB5KRB_ERR_GENERIC:
default:
return ERR_INTERNAL;
}
}
{
int ret;
krb5_error_code kerr = 0;
const char *newpassword = NULL;
int result_code = -1;
char *user_error_message = NULL;
const char *realm_name;
int realm_length;
"Failed to fetch current password [%d] %s.\n",
return ERR_NO_CREDS;
}
if (!prelim) {
/* We do not need a password expiration warning here. */
}
if (realm_length == 0) {
return ERR_INTERNAL;
}
"Attempting kinit for realm [%s]\n",realm_name);
if (kerr != 0) {
"pack_user_info_chpass_error failed.\n");
} else {
msg);
"pam_add_response failed.\n");
}
}
return kerr;
}
if (prelim) {
"Initial authentication for change password operation "
"successful.\n");
return EOK;
}
return ERR_NO_CREDS;
}
if (kerr == KRB5_KDC_UNREACH) {
return ERR_NETWORK_IO;
}
if (kerr != 0 || result_code != 0) {
if (kerr != 0) {
}
if (result_code_string.length > 0) {
"krb5_change_password failed [%d][%.*s].\n", result_code,
if (user_error_message == NULL) {
}
}
"krb5_change_password failed [%d][%.*s].\n", result_code,
if (user_error_message == NULL) {
}
} else if (result_code == KRB5_KPASSWD_SOFTERROR) {
"password meets the complexity constraints.");
if (user_error_message == NULL) {
}
}
if (user_error_message != NULL) {
&user_resp_len, &user_resp);
"pack_user_info_chpass_error failed.\n");
} else {
"pack_response_packet failed.\n");
}
}
}
return ERR_CHPASS_FAILED;
}
(const uint8_t *) &user_info_type);
/* Not fatal */
}
return map_krb5_error(kerr);
}
/* We changed some of the gic options for the password change, now we have
* to change them back to get a fresh TGT. */
if (kerr == 0) {
}
return map_krb5_error(kerr);
}
{
int ret;
/* No password is needed for pre-auth, or if we have 2FA */
switch (ret) {
case EOK:
break;
case EACCES:
return ERR_INVALID_CRED_TYPE;
break;
default:
return ERR_NO_CREDS;
break;
}
}
if (kerr != KRB5KDC_ERR_KEY_EXP) {
/* add OTP tokeninfo messge if available */
}
} else {
if (kerr == 0) {
}
}
goto done;
}
/* If the password is expired the KDC will always return
KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or
not. In general the password can still be used to get a changepw ticket.
So we validate the password by trying to get a changepw ticket. */
if (kerr != 0) {
"Failed to unset expire callback, continue ...\n");
}
sss_krb5_prompter, kr, 0,
if (kerr == 0) {
/* If the password is expired we can safely remove the ccache from the
* cache and disk if it is not actively used anymore. This will allow
* to create a new random ccache if sshd with privilege separation is
* used. */
"Failed to remove old ccache file [%s], "
}
}
} else {
}
done:
return ret;
}
{
/* krb5_kuserok tries to verify that kr->pd->user is a locally known
* account, so we have to unset _SSS_LOOPS to make getpwnam() work. */
if (unsetenv("_SSS_LOOPS") != 0) {
"krb5_kuserok will most certainly fail.\n");
}
if (kerr != 0) {
"krb5_kuserok may fail.\n");
}
if (access_allowed) {
return EOK;
}
return ERR_AUTH_DENIED;
}
{
const char *ccname;
int ret;
"Unsupported authtok type for TGT renewal [%d].\n",
return ERR_INVALID_CRED_TYPE;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
} else {
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
"add_ticket_times_and_upn_to_response failed.\n");
}
done:
}
return map_krb5_error(kerr);
}
{
if (kr->old_cc_valid == false) {
if (kerr == 0) {
}
} else {
kerr = 0;
}
if (kerr == 0) {
}
return map_krb5_error(kerr);
}
{
if ((*p + auth_token_length) > size) {
return EINVAL;
}
switch (auth_token_type) {
case SSS_AUTHTOK_TYPE_EMPTY:
break;
break;
case SSS_AUTHTOK_TYPE_CCFILE:
break;
case SSS_AUTHTOK_TYPE_2FA:
break;
default:
return EINVAL;
}
*p += auth_token_length;
}
return ret;
}
{
size_t p = 0;
return ENOMEM;
}
p += len;
"cmd [%d] uid [%llu] gid [%llu] validate [%s] "
"enterprise principal [%s] offline [%s] UPN [%s]\n",
p += len;
if (len > 0) {
p += len;
} else {
}
p += len;
if (ret) {
return ret;
}
"ccname: [%s] old_ccname: [%s] keytab: [%s]\n",
} else {
}
if (ret) {
return ret;
}
} else {
}
p += len;
} else {
}
return EOK;
}
{
}
}
return EOK;
}
{
if (krberr != 0) {
goto done;
}
if (krberr == KRB5_FCC_NOFILE) {
} else if (krberr != 0) {
krberr = 0;
goto done;
}
krberr = 0;
done:
}
return krberr;
}
const char *primary,
const char *realm,
const char *keytab_name,
char **fast_ccname)
{
char *ccname;
char *server_name;
int status;
return ENOMEM;
}
goto done;
}
if (keytab_name != NULL) {
} else {
}
if (kerr) {
"Failed to read keytab file [%s]: %s\n",
goto done;
}
if (kerr != 0) {
"find_principal_in_keytab failed for principal %s@%s.\n",
goto done;
}
if (server_name == NULL) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr == 0) {
goto done;
}
}
/* Need to recreate the FAST ccache */
fchild_pid = fork();
switch (fchild_pid) {
case -1:
goto done;
case 0:
/* Child */
if (debug_prg_name == NULL) {
debug_prg_name = "[sssd[krb5_child]]";
/* Try to carry on */
}
if (kerr != 0) {
exit(1);
}
if (kerr != 0) {
"get_and_save_tgt_with_keytab failed: %d\n", kerr);
exit(2);
}
exit(0);
default:
/* Parent */
do {
errno = 0;
if (kerr > 0) {
/* Don't blindly fail if the child fails, but check
* the ccache again */
if (kerr != 0) {
"Creating FAST ccache failed, krb5_child will "
"likely fail!\n");
}
} else {
"krb5_child subprocess %d terminated unexpectedly\n",
}
} else {
"Failed to wait for child %d\n", fchild_pid);
/* Let the code re-check the TGT times and fail if we
* can't find the updated principal */
}
}
/* Check the ccache times again. Should be updated ... */
if (kerr != 0) {
goto done;
}
"FAST TGT was renewed but is already expired, please check that "
"time is synchronized with server.\n");
goto done;
}
done:
if (client_princ != NULL) {
}
if (server_princ != NULL) {
}
if (kerr == 0) {
}
}
return kerr;
}
{
errno = 0;
if (len == -1) {
return ret;
}
}
return ret;
}
{
char *fast_principal_realm;
char *fast_principal;
char *tmp_str;
char *new_ccname;
if (tmp_str) {
if (kerr) {
return kerr;
}
&tmp_str);
if (kerr) {
return kerr;
}
if (!fast_principal) {
return KRB5KRB_ERR_GENERIC;
}
if (!fast_principal_realm) {
return ENOMEM;
}
} else {
}
if (kerr != 0) {
return kerr;
}
if (kerr != 0) {
return kerr;
}
kr->fast_ccname);
if (kerr != 0) {
"sss_krb5_get_init_creds_opt_set_fast_ccache_name "
"failed.\n");
return kerr;
}
if (demand) {
if (kerr != 0) {
"sss_krb5_get_init_creds_opt_set_fast_flags "
"failed.\n");
return kerr;
}
}
return EOK;
}
{
char *use_fast_str;
enum k5c_fast_opt fast_val;
} else {
"Unsupported value [%s] for krb5_use_fast.\n",
return EINVAL;
}
return EOK;
}
{
bool valid;
valid = false;
switch (ret) {
case ERR_NOT_FOUND:
case ENOENT:
break;
case EINVAL:
/* cache found but no tgt or expired */
case EOK:
valid = true;
break;
default:
"Cannot check if saved ccache %s is valid\n",
kr->old_ccname);
return ret;
}
return EOK;
}
{
if (kr->old_ccname) {
return ret;
}
return ret;
}
"Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
}
return EOK;
}
{
/* The ccache file should be (re)created if one of the following conditions
* is true:
* - it doesn't exist (kr->old_ccname == NULL)
* - the backend is online and the current ccache file is not used, i.e
* the related user is currently not logged in and it is not a renewal
* request
* (offline && !kr->old_cc_active && kr->pd->cmd != SSS_CMD_RENEW)
* - the backend is offline and the current cache file not used and
* it does not contain a valid tgt
* (offline && !kr->old_cc_active && !kr->valid_tgt)
*/
return ret;
}
} else {
/* We can reuse the old ccache */
}
return EOK;
}
{
return EOK;
}
if (ret != 0) {
"Assuming old cache is invalid " \
"and not used.\n",
}
/* Pre-creating the ccache must be done as root, otherwise we can't mkdir
* logind doesn't create the directory until the session phase, whereas
* we need the directory during the auth phase already
*/
if (ret != 0) {
return ret;
}
return EOK;
}
{
int parse_flags;
/* If krb5_child was started as setuid, but we don't need to
* perform either validation or FAST, just drop privileges to
* the user who is logging in. The same applies to the offline case
* the user who is logging in. The same applies to the offline case.
*/
if (kerr != 0) {
return kerr;
}
}
/* Set the global error context */
if (debug_level & SSSDBG_TRACE_ALL) {
if (kerr != 0) {
return EIO;
}
}
/* Enterprise principals require that a default realm is available. To
* make SSSD more robust in the case that the default realm option is
* missing in krb5.conf or to allow SSSD to work with multiple unconnected
* realms (e.g. AD domains without trust between them) the default realm
* will be set explicitly. */
if (kr->use_enterprise_princ) {
if (kerr != 0) {
}
}
if (kerr != 0) {
return kerr;
}
if (kerr != 0) {
return kerr;
}
return ENOMEM;
}
if (kerr != 0) {
return kerr;
}
#endif
/* A prompter is used to catch messages about when a password will
* expired. The library shall not use the prompter to ask for a new password
* but shall return KRB5KDC_ERR_KEY_EXP. */
#endif
if (kerr != 0) {
return kerr;
}
if (!offline) {
}
/* TODO: set options, e.g.
* krb5_get_init_creds_opt_set_forwardable
* krb5_get_init_creds_opt_set_proxiable
* krb5_get_init_creds_opt_set_etype_list
* krb5_get_init_creds_opt_set_address_list
* krb5_get_init_creds_opt_set_preauth_list
* krb5_get_init_creds_opt_set_salt
* krb5_get_init_creds_opt_set_change_password_prompt
* krb5_get_init_creds_opt_set_pa
*/
return kerr;
}
{
int ret;
char *mem_keytab;
"Cannot read [%s] from environment.\n", SSSD_KRB5_REALM);
}
if (kerr != 0) {
return kerr;
}
if (kerr != 0) {
return kerr;
}
return ret;;
}
/* For ccache types FILE: and DIR: we might need to create some directory
* components as root. Cache files are not needed during preauth. */
return ret;
}
}
if (!(offline ||
NULL);
if (kerr != 0) {
return kerr;
}
return kerr;
}
}
}
/* Not fatal */
}
}
return 0;
}
{
int opt;
int debug_fd = -1;
struct poptOption long_options[] = {
_("Debug level"), NULL},
_("Add debug timestamps"), NULL},
_("Show timestamps with microseconds"), NULL},
_("An open file descriptor for the debug logs"), NULL},
&debug_to_stderr, 0,
_("Send the debug output to stderr directly."), NULL },
_("The user to create FAST ccache as"), NULL},
_("The group to create FAST ccache as"), NULL},
};
/* Set debug level to invalid value so we can decide if -d 0 was used. */
switch(opt) {
default:
_exit(-1);
}
}
if (!debug_prg_name) {
debug_prg_name = "[sssd[krb5_child]]";
goto done;
}
if (debug_fd != -1) {
}
}
goto done;
}
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
goto done;
}
case SSS_PAM_AUTHENTICATE:
/* If we are offline, we need to create an empty ccache file */
if (offline) {
} else {
}
break;
case SSS_PAM_CHAUTHTOK:
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
break;
case SSS_PAM_ACCT_MGMT:
break;
case SSS_CMD_RENEW:
if (offline) {
goto done;
}
break;
case SSS_PAM_PREAUTH:
break;
default:
goto done;
}
}
done:
ret = 0;
} else {
ret = -1;
}
}