/** * @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)); }
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; }
int sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth, struct sudo_conv_callback *callback) { struct passwd temp_pw; sec_passwd_rec_t password_rec; sec_login_handle_t login_context; boolean32 reset_passwd; sec_login_auth_src_t auth_src; error_status_t status; debug_decl(sudo_dce_verify, SUDOERS_DEBUG_AUTH) /* * Create the local context of the DCE principal necessary * to perform authenticated network operations. The network * identity set up by this operation cannot be used until it * is validated via sec_login_validate_identity(). */ if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, sec_login_no_flags, &login_context, &status)) { if (check_dce_status(status, "sec_login_setup_identity(1):")) debug_return_int(AUTH_FAILURE); password_rec.key.key_type = sec_passwd_plain; password_rec.key.tagged_union.plain = (idl_char *) plain_pw; password_rec.pepper = NULL; password_rec.version_number = sec_passwd_c_version_none; /* Validate the login context with the password */ if (sec_login_validate_identity(login_context, &password_rec, &reset_passwd, &auth_src, &status)) { if (check_dce_status(status, "sec_login_validate_identity(1):")) debug_return_int(AUTH_FAILURE); /* * Certify that the DCE Security Server used to set * up and validate a login context is legitimate. Makes * sure that we didn't get spoofed by another DCE server. */ if (!sec_login_certify_identity(login_context, &status)) { sudo_printf(SUDO_CONV_ERROR_MSG, "Whoa! Bogus authentication server!\n"); (void) check_dce_status(status,"sec_login_certify_identity(1):"); debug_return_int(AUTH_FAILURE); } if (check_dce_status(status, "sec_login_certify_identity(2):")) debug_return_int(AUTH_FAILURE); /* * Sets the network credentials to those specified * by the now validated login context. */ sec_login_set_context(login_context, &status); if (check_dce_status(status, "sec_login_set_context:")) debug_return_int(AUTH_FAILURE); /* * Oops, your credentials were no good. Possibly * caused by clock times out of adjustment between * DCE client and DCE security server... */ if (auth_src != sec_login_auth_src_network) { sudo_printf(SUDO_CONV_ERROR_MSG, "You have no network credentials.\n"); debug_return_int(AUTH_FAILURE); } /* Check if the password has aged and is thus no good */ if (reset_passwd) { sudo_printf(SUDO_CONV_ERROR_MSG, "Your DCE password needs resetting.\n"); debug_return_int(AUTH_FAILURE); } /* * We should be a valid user by this point. Pull the * user's password structure from the DCE security * server just to make sure. If we get it with no * problems, then we really are legitimate... */ sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw, &status); if (check_dce_status(status, "sec_login_get_pwent:")) debug_return_int(AUTH_FAILURE); /* * If we get to here, then the pwent above properly fetched * the password structure from the DCE registry, so the user * must be valid. We don't really care what the user's * registry password is, just that the user could be * validated. In fact, if we tried to compare the local * password to the DCE entry at this point, the operation * would fail if the hidden password feature is turned on, * because the password field would contain an asterisk. * Also go ahead and destroy the user's DCE login context * before we leave here (and don't bother checking the * status), in order to clean up credentials files in * /opt/dcelocal/var/security/creds. By doing this, we are * assuming that the user will not need DCE authentication * later in the program, only local authentication. If this * is not true, then the login_context will have to be * returned to the calling program, and the context purged * somewhere later in the program. */ sec_login_purge_context(&login_context, &status); debug_return_int(AUTH_SUCCESS); } else { if(check_dce_status(status, "sec_login_validate_identity(2):")) debug_return_int(AUTH_FAILURE); sec_login_purge_context(&login_context, &status); if(check_dce_status(status, "sec_login_purge_context:")) debug_return_int(AUTH_FAILURE); } } (void) check_dce_status(status, "sec_login_setup_identity(2):"); debug_return_int(AUTH_FAILURE); }
/** * @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); }