/** * @brief * renews the login context after certain time * * @param[in] lcon - structure handle for sec_login * * @return - time_t * @retval retry_time(now + SHORT_TIME) - refresh failure * validation failure * @retval refresh_time Success * */ time_t do_refresh(sec_login_handle_t lcon) { error_status_t st; time_t now = time(NULL); time_t retry_time = now + SHORT_TIME; boolean32 reset_passwd; sec_login_auth_src_t auth_src; if (!sec_login_refresh_identity(lcon, &st)) { /* fail refresh */ if (st == error_status_ok) { fprintf(stderr, "sec_login_refresh_identity fail - reason??\n"); } else { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "identity refresh fail - %s\n", err_string); } return retry_time; } else { /* refresh successful, try to validate */ fill_pwdrec((char*)&tmp_passwd[0], &pwdrec); if (!sec_login_validate_identity(lcon, &pwdrec, &reset_passwd, &auth_src, &st)) { /* fail validate */ if (st == error_status_ok) { fprintf(stderr, "sec_login_validate_identity fail - reason??\n"); } else { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "validate refresh fail - %s\n", err_string); } return retry_time; } else { /* refreshed and validated */ /* verify login_context is from trusted security server */ /* needed for error_status_ok from sec_login_get_expiration */ if (!sec_login_certify_identity(lcon, &st)) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "failed certification of login_context for %s - %s\n", username, err_string); } } } return (compute_refresh_time(lcon)); }
/* AIX with DCE 1.1 does not have the com_err in the libdce.a * do a half hearted job of substituting for it. */ void com_err(char *p1, int code, ...) { int lst; dce_error_string_t err_string; dce_error_inq_text(code, err_string, &lst); fprintf(stderr,"Error %d in %s: %s\n", code, p1, err_string ); }
/* Returns 0 for DCE "ok" status, 1 otherwise */ static int check_dce_status(error_status_t input_status, char *comment) { int error_stat; unsigned char error_string[dce_c_error_string_len]; debug_decl(check_dce_status, SUDOERS_DEBUG_AUTH) if (input_status == rpc_s_ok) debug_return_int(0); dce_error_inq_text(input_status, error_string, &error_stat); sudo_printf(SUDO_CONV_ERROR_MSG, "%s %s\n", comment, error_string); debug_return_int(1); }
/* Returns 0 for DCE "ok" status, 1 otherwise */ static int check_dce_status(error_status_t input_status, char *comment) { int error_stat; unsigned char error_string[dce_c_error_string_len]; debug_decl(check_dce_status, SUDO_DEBUG_AUTH) if (input_status == rpc_s_ok) debug_return_bool(0); dce_error_inq_text(input_status, error_string, &error_stat); (void) fprintf(stderr, "%s %s\n", comment, error_string); debug_return_bool(1); }
void dfs_unlogin(void) { error_status_t err; int err2; unsigned char dce_errstr[dce_c_error_string_len]; sec_login_purge_context(my_dce_sec_context, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE purge login context failed for server instance %d: %s\n", getpid(), dce_errstr)); } }
/** * @brief * Removes the dce login context in case of fork fail * or child finishes its task. * * @return - Error code * @retval -1 Failure * @retval 0 Success * */ int remove_context() { error_status_t st; if (have_login_context) { sec_login_purge_context(&lcon, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "Error purging DCE login context for %s - cache not destroyed\n", username, err_string); return (-1); } have_login_context = 0; } return (0); }
/** * @brief * compute_refresh_time - We have a refreshed login context, use it in * computing the next refresh time point. * * This function is the merge (and modification) of the two original functions, * compute_expire_delta() and compute_alarm_time(). * * @param[in] lcon - structure handle for sec_login * * @return - time_t * @retval 0 if remaining TGT lifetime < 10minutes or, * if computed refresh time exceeds expiration time * @retval (now + computed refresh_delta) otherwise. * */ time_t compute_refresh_time(sec_login_handle_t lcon) { error_status_t st; signed32 expire_time = -1; time_t expire_delta, refresh_delta, refresh_time; time_t now = time(NULL); /* get lifetime of the context's tgt */ expire_delta = -1; (void)sec_login_get_expiration(lcon, &expire_time, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "failed getting login context expiration time - %s\n", err_string); } else if (expire_time <= 0) { fprintf(stderr, "Got a bad context expiration time for context\n"); } else /* compute expire delta */ expire_delta = expire_time - now; /* life of tgt < 10 minutes, don't bother doing refreshes */ if (expire_delta <= SHORT_TIME) return 0; refresh_delta = expire_delta * 80 / 100; if (refresh_delta < SHORT_TIME) refresh_delta = SHORT_TIME; refresh_time = refresh_delta + now; if (refresh_time > expire_time) return 0; return refresh_time; }
/******************************************************************* check on a DCE/DFS authentication ********************************************************************/ static BOOL dfs_auth(char *this_user,char *password) { error_status_t err; int err2; int prterr; boolean32 password_reset; sec_passwd_rec_t my_dce_password; sec_login_auth_src_t auth_src = sec_login_auth_src_network; unsigned char dce_errstr[dce_c_error_string_len]; /* * We only go for a DCE login context if the given password * matches that stored in the local password file.. * Assumes local passwd file is kept in sync w/ DCE RGY! */ /* Fix for original (broken) code from Brett Wooldridge <*****@*****.**> */ if (dcelogin_atmost_once) return (False); /* This can be ifdefed as the DCE check below is stricter... */ #ifndef NO_CRYPT if ( strcmp((char *)crypt(password,this_salt),this_crypted) ) return (False); #endif if (sec_login_setup_identity( (unsigned char *)this_user, sec_login_no_flags, &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE Setup Identity for %s failed: %s\n", this_user,dce_errstr)); return(False); } my_dce_password.version_number = sec_passwd_c_version_none; my_dce_password.pepper = NULL; my_dce_password.key.key_type = sec_passwd_plain; my_dce_password.key.tagged_union.plain = (idl_char *)password; if (sec_login_valid_and_cert_ident(my_dce_sec_context, &my_dce_password, &password_reset, &auth_src, &err) == 0 ) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n", this_user,dce_errstr)); return(False); } sec_login_set_context(my_dce_sec_context, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n", this_user,dce_errstr)); sec_login_purge_context(my_dce_sec_context, &err); return(False); } else { DEBUG(0,("DCE login succeeded for principal %s on pid %d\n", this_user, getpid())); } dcelogin_atmost_once = 1; return (True); }
int gsslib_put_credentials(gss_cred_id_t server_creds, gss_buffer_desc *cred, char *username) { gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_buffer_desc client_name; OM_uint32 maj_stat, min_stat; GSSAPI_INT ret_flags; gss_buffer_desc send_tok; gss_name_t client = NULL; gss_OID doid; int cc=0; gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL; gsslib_reset_error(); send_tok.length = 0; client_name.length = 0; if (cred->length <= 0) { gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALBUFFERLENGTHISZERO ); cc = -1; goto error; } /* * establish and forward client credentials */ maj_stat = gss_accept_sec_context(&min_stat, &context, server_creds, cred, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid, &send_tok, &ret_flags, NULL, /* ignore time_rec */ &delegated_cred); /* ignore del_cred_handle */ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_ACCEPTINGCONTEXT, maj_stat, min_stat); cc = -1; goto error; } if (send_tok.length != 0) { fprintf(stderr, "%s\n", MSG_GSS_ACCEPTSECCONTEXTREQUIRESTOKENTOBESENTBACK ); /* cc = -1; goto error; */ } maj_stat = gss_display_name(&min_stat, client, &client_name, &doid); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat); cc = -1; goto error; } #ifdef KRBGSS #ifdef KRB5_EXPORTVAR /* this is required for later Kerberos versions */ /* check for delegated credential */ if (delegated_cred == GSS_C_NO_CREDENTIAL) { fprintf(stderr, "WARNING: Credentials were not forwarded\n"); #ifdef REQUIRE_FORWARDED_CREDENTIALS cc = 3; goto error; #endif } if (username && (ret_flags & GSS_C_DELEG_FLAG)) { char *principal = malloc(client_name.length + 1); strncpy(principal, client_name.value, client_name.length); principal[client_name.length] = 0; put_creds_in_ccache(principal, delegated_cred); free(principal); } #endif #endif /* display the flags */ if (verbose) gsslib_display_ctx_flags(ret_flags); if (verbose) printf("client: \"%.*s\"\n", (int) client_name.length, (char *) client_name.value); if (username) { gss_buffer_desc tok; gss_name_t user_name; int str_equal; tok.value = username; tok.length = strlen(tok.value)+1; maj_stat = gss_import_name(&min_stat, &tok, GSS_C_NULL_OID, &user_name); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_PARSINGNAME, maj_stat, min_stat); cc = -1; goto error; } maj_stat = gss_compare_name(&min_stat, client, user_name, &str_equal); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status( MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat); cc = 6; goto error; } #ifdef KRBGSS if (!str_equal) { krb5_context context; maj_stat = krb5_init_context(&context); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GETTINGKRB5CONTEXT, maj_stat, GSS_S_COMPLETE); cc = -1; goto error; } /* see if this user is authorized by the krb5 client */ if (krb5_kuserok(context, (krb5_principal)client, username)) str_equal = 1; } /* Users from Kerberos cross-authenticated realms will not match, so we manually compare the user names */ if (!str_equal) { char *s; if ((s=strchr((char *)client_name.value, '@'))) str_equal = !strncmp(username, (char *)client_name.value, s-(char *)client_name.value); } #endif if (!str_equal) { char buf[1024]; snprintf(buf, sizeof(buf), MSG_GSS_CLIENTNAMEXDOESNOTMATCHUNAMEY_SS, (int)client_name.length, (char *)client_name.value, username); gsslib_print_error(buf); cc = 5; goto error; } } #ifdef DCE while (delegated_cred) { sec_login_handle_t login_context; error_status_t st; dce_error_string_t err_string; int lst; sec_login_auth_src_t auth_src=NULL; boolean32 reset_passwd=0; char errbuf[1024]; unsigned32 num_groups=0; signed32 *groups=NULL; unsigned32 flags; maj_stat = gssdce_set_cred_context_ownership(&min_stat, delegated_cred, GSSDCE_C_OWNERSHIP_APPLICATION); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCESETCREDCONTEXTOWNERSHIP, maj_stat, min_stat); break; } #if 0 gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALDUMP); gsslib_print_error(dump_cred(delegated_cred)); #endif maj_stat = gssdce_cred_to_login_context(&min_stat, delegated_cred, &login_context); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCECREDTOLOGINCONTEXT, maj_stat, min_stat); break; } #ifdef TURN_OFF_DELEGATION { sec_login_handle_t *new_login_context; new_login_context = sec_login_disable_delegation(login_context, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTDISABLEDELEGATIONX_S, err_string); gsslib_print_error(errbuf); } else { login_context = *new_login_context; } } #endif flags = sec_login_get_context_flags(login_context, &st); sec_login_set_context_flags(login_context, flags & ~sec_login_credentials_private, &st); if (!sec_login_certify_identity(login_context, &st)) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTCERTIFYIDENTITYX_S, err_string); gsslib_print_error(errbuf); break; } sec_login_set_context(login_context, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &lst); snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_COULDNOTSETUPLOGINCONTEXTX_S, err_string); gsslib_print_error(errbuf); break; } { char *cp; cp = getenv("KRB5CCNAME"); if (cp) { snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_NEWKRB5CCNAMEISX_S , cp); gsslib_print_error(errbuf); } else { gsslib_print_error(MSG_GSS_PRINTERROR_KRB5CCNAMENOTFOUND ); } } break; } #endif /* DCE */ error: if (client) { maj_stat = gss_release_name(&min_stat, &client); if (maj_stat != GSS_S_COMPLETE) { gsslib_display_status(MSG_GSS_DISPLAYSTATUS_RELEASINGNAME, maj_stat, min_stat); cc = -1; } } if (send_tok.length) (void) gss_release_buffer(&min_stat, &send_tok); if (client_name.length) (void) gss_release_buffer(&min_stat, &client_name); return cc; }
/** * @brief * establishes the dce login context by validating the security credentials * username and password. * * @param[in] username - username for validation * * @return - Error code * @retval 253 - sec_login_setup_identity was not successful * 254 - the validate call did not return success * @retval 0 Success * */ int establish_login_context(char *username) { error_status_t st; sec_login_auth_src_t auth_src; boolean32 reset_passwd; if (sec_login_setup_identity((unsigned_char_p_t)username, sec_login_no_flags, &lcon, &st)) { /* now validate the login context information */ fill_pwdrec((char*)&tmp_passwd[0], &pwdrec); if (sec_login_validate_identity(lcon, &pwdrec, &reset_passwd, &auth_src, &st)) { /* verify login_context is from trusted security server */ if (!sec_login_certify_identity(lcon, &st)) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "Didn't certify login_context for %s - %s\n", username, err_string); } /* notify user if password valid period expired */ if (reset_passwd) { fprintf(stderr, "Password must be changed for %s\n", username); } /* authentication frm netwrk security server or local host? */ if (auth_src == sec_login_auth_src_local) { fprintf(stderr, "Credential source for %s is local registry\n", username); } if (auth_src == sec_login_auth_src_overridden) { fprintf(stderr, "Credential source for %s is overridden\n", username); } /* finally, set this context as the current context */ /* DCE cache files created upon success on this step*/ sec_login_set_context(lcon, &st); if (st != error_status_ok) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "Couldn't set context for %s - %s\n", username, err_string); } /* end of sequece (validate, certify, set context) */ } else { /* the validate call did not return success */ if (st != error_status_ok) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "Unable to validate security context for %s - %s\n", username, err_string); } else { fprintf(stderr, "sec_login_validate_identity failed - reason??\n"); } return (254); } } else { /* sec_login_setup_identity was not successful */ if (st != error_status_ok) { dce_error_inq_text(st, err_string, &inq_st); fprintf(stderr, "Unable to setup login entry for %s because %s\n", username, err_string); } else { fprintf(stderr, "sec_login_setup_identity failed - reason??\n"); } return (253); } return (0); }
/******************************************************************* check on a DCE/DFS authentication ********************************************************************/ static BOOL dfs_auth(char *user, char *password) { error_status_t err; int err2; int prterr; signed32 expire_time, current_time; boolean32 password_reset; struct passwd *pw; sec_passwd_rec_t passwd_rec; sec_login_auth_src_t auth_src = sec_login_auth_src_network; unsigned char dce_errstr[dce_c_error_string_len]; gid_t egid; if (dcelogin_atmost_once) return (False); #ifdef HAVE_CRYPT /* * We only go for a DCE login context if the given password * matches that stored in the local password file.. * Assumes local passwd file is kept in sync w/ DCE RGY! */ if (strcmp((char *)crypt(password, this_salt), this_crypted)) { return (False); } #endif sec_login_get_current_context(&my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); return (False); } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); return (False); } sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); return (False); } time(¤t_time); if (expire_time < (current_time + 60)) { struct passwd *pw; sec_passwd_rec_t *key; sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); return (False); } sec_login_refresh_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't refresh identity. %s\n", dce_errstr)); return (False); } sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL, (unsigned char *)pw->pw_name, sec_c_key_version_none, (void **)&key, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get key for %s. %s\n", pw->pw_name, dce_errstr)); return (False); } sec_login_valid_and_cert_ident(my_dce_sec_context, key, &password_reset, &auth_src, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't validate and certify identity for %s. %s\n", pw->pw_name, dce_errstr)); } sec_key_mgmt_free_key(key, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't free key.\n", dce_errstr)); } } if (sec_login_setup_identity((unsigned char *)user, sec_login_no_flags, &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", user, dce_errstr)); return (False); } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); return (False); } sec_login_purge_context(&my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr)); return (False); } /* * NB. I'd like to change these to call something like change_to_user() * instead but currently we don't have a connection * context to become the correct user. This is already * fairly platform specific code however, so I think * this should be ok. I have added code to go * back to being root on error though. JRA. */ egid = getegid(); set_effective_gid(pw->pw_gid); set_effective_uid(pw->pw_uid); if (sec_login_setup_identity((unsigned char *)user, sec_login_no_flags, &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", user, dce_errstr)); goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); goto err; } passwd_rec.version_number = sec_passwd_c_version_none; passwd_rec.pepper = NULL; passwd_rec.key.key_type = sec_passwd_plain; passwd_rec.key.tagged_union.plain = (idl_char *) password; sec_login_validate_identity(my_dce_sec_context, &passwd_rec, &password_reset, &auth_src, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Identity Validation failed for principal %s: %s\n", user, dce_errstr)); goto err; } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr)); goto err; } if (auth_src != sec_login_auth_src_network) { DEBUG(0, ("DCE context has no network credentials.\n")); } sec_login_set_context(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE login failed for principal %s, cant set context: %s\n", user, dce_errstr)); sec_login_purge_context(&my_dce_sec_context, &err); goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); goto err; } DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n", user, sys_getpid())); DEBUG(3, ("DCE principal: %s\n" " uid: %d\n" " gid: %d\n", pw->pw_name, pw->pw_uid, pw->pw_gid)); DEBUG(3, (" info: %s\n" " dir: %s\n" " shell: %s\n", pw->pw_gecos, pw->pw_dir, pw->pw_shell)); sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); goto err; } set_effective_uid(0); set_effective_gid(0); DEBUG(0, ("DCE context expires: %s", asctime(localtime(&expire_time)))); dcelogin_atmost_once = 1; return (True); err: /* Go back to root, JRA. */ set_effective_uid(0); set_effective_gid(egid); return (False); }