From ef83172addd8ee5a40d7ae52d1c03ffd7eb2803b Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Wed, 15 Jun 1994 05:00:32 +0000 Subject: [PATCH] Included fixes submitted by Ari/Cliff, including a security fix git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3797 dc483132-0cff-0310-8789-dd5450dbe970 --- src/clients/ksu/Imakefile | 13 +- src/clients/ksu/ccache.c | 91 +++--- src/clients/ksu/heuristic.c | 89 +++--- src/clients/ksu/krb_auth_su.c | 62 ++++- src/clients/ksu/ksu.M | 505 ++++++++++++++++++++++++++++++++++ src/clients/ksu/ksu.h | 9 +- src/clients/ksu/main.c | 288 ++++++++++++------- 7 files changed, 855 insertions(+), 202 deletions(-) create mode 100644 src/clients/ksu/ksu.M diff --git a/src/clients/ksu/Imakefile b/src/clients/ksu/Imakefile index d34819423..cce252615 100644 --- a/src/clients/ksu/Imakefile +++ b/src/clients/ksu/Imakefile @@ -22,15 +22,20 @@ # or implied warranty. # # - DEPLIBS = $(DEPKLIB) + +DEPLIBS = $(DEPKLIB) LOCAL_LIBRARIES = $(KLIB) +DEFINES = -DLOCAL_REALM='"."' -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"' + OBJS = krb_auth_su.o ccache.o authorization.o main.o heuristic.o SRCS = krb_auth_su.c ccache.c authorization.c main.c heuristic.c -all:: ksu +all:: ksu NormalProgramTarget(ksu,$(OBJS),$(DEPLIBS),$(LOCAL_LIBRARIES),) -Krb5InstallClientProgram(ksu) -DependTarget() +InstallProgramWithFlags(ksu,$(CLIENT_BINDIR),$(INSTUIDFLAGS)) +Krb5InstallManPage(ksu,$(CLIENT_MANDIR),$(CLIENT_MANSUFFIX)) + +DependTarget() diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c index 38410b977..b778af87b 100644 --- a/src/clients/ksu/ccache.c +++ b/src/clients/ksu/ccache.c @@ -47,7 +47,7 @@ krb5_error_code krb5_ccache_copy (/* IN */ krb5_ccache cc_def, char * cc_other_tag, krb5_principal primary_principal, /* OUT */ - krb5_ccache * cc_out ){ + krb5_ccache * cc_out, krb5_boolean * stored){ int i=0; krb5_ccache * cc_other; @@ -60,6 +60,7 @@ int code= 0; krb5_creds ** cc_def_creds_arr = NULL; krb5_creds ** cc_other_creds_arr = NULL; uid_t eff_uid, eff_gid; +struct stat st_temp; cc_other = (krb5_ccache *) calloc(1, sizeof (krb5_ccache)); @@ -72,32 +73,22 @@ uid_t eff_uid, eff_gid; cc_def_name = krb5_cc_get_name(cc_def); cc_other_name = krb5_cc_get_name(*cc_other); - if ( ! access(cc_def_name, F_OK)){ + if ( ! stat(cc_def_name, &st_temp)){ if(retval = krb5_get_nonexp_tkts( cc_def, &cc_def_creds_arr)){ return retval; } } + *stored = krb5_find_princ_in_cred_list(cc_def_creds_arr,primary_principal); - eff_uid = geteuid(); - eff_gid = getegid(); - - if (seteuid(getuid()) < 0) { return errno;} - if (setegid(getgid()) < 0) { return errno;} if (retval = krb5_cc_initialize(*cc_other, primary_principal)){ return retval; } - if (seteuid(eff_uid) < 0) {return errno; } - if (setegid(eff_gid) < 0) {return errno; } - - retval = krb5_store_all_creds(* cc_other, cc_def_creds_arr, cc_other_creds_arr); - - if (cc_def_creds_arr){ while (cc_def_creds_arr[i]){ krb5_free_creds(cc_def_creds_arr[i]); @@ -498,7 +489,7 @@ show_credential(krb5_creds * cred, krb5_ccache cc) free(sname); } -int gen_sim(){ +int gen_sym(){ static int i = 0; i ++; return i; @@ -513,17 +504,18 @@ krb5_principal temp_principal; krb5_creds ** ccs_creds_arr = NULL; int i=0; uid_t eff_uid, eff_gid; +struct stat st_temp; ccs_name = krb5_cc_get_name(ccs); cct_name = krb5_cc_get_name(cct); - if ( ! access(ccs_name, F_OK)){ + if ( ! stat(ccs_name, &st_temp)){ if(retval = krb5_get_nonexp_tkts( ccs, &ccs_creds_arr)){ return retval; } } - if ( ! access(cct_name, F_OK)){ + if ( ! stat(cct_name, &st_temp)){ if (retval = krb5_cc_get_principal(cct, &temp_principal)){ return retval; } @@ -531,17 +523,9 @@ uid_t eff_uid, eff_gid; temp_principal = primary_principal; } - eff_uid = geteuid(); - eff_gid = getegid(); - - if (seteuid(getuid()) < 0) { return errno;} - if (setegid(getgid()) < 0) { return errno;} - if (retval = krb5_cc_initialize(cct, temp_principal)){ return retval; } - if (seteuid(eff_uid) < 0) {return errno; } - if (setegid(eff_gid) < 0) {return errno; } retval = krb5_store_all_creds(cct, ccs_creds_arr, NULL); @@ -628,6 +612,7 @@ int code= 0; krb5_creds ** cc_def_creds_arr = NULL; krb5_creds ** cc_other_creds_arr = NULL; uid_t eff_uid, eff_gid; +struct stat st_temp; cc_other = (krb5_ccache *) calloc(1, sizeof (krb5_ccache)); @@ -640,27 +625,17 @@ uid_t eff_uid, eff_gid; cc_def_name = krb5_cc_get_name(cc_def); cc_other_name = krb5_cc_get_name(*cc_other); - if ( ! access(cc_def_name, F_OK)){ + if ( ! stat(cc_def_name, &st_temp)){ if(retval = krb5_get_nonexp_tkts( cc_def, &cc_def_creds_arr)){ return retval; } } - eff_uid = geteuid(); - eff_gid = getegid(); - - if (seteuid(getuid()) < 0) { return errno;} - if (setegid(getgid()) < 0) { return errno;} - if (retval = krb5_cc_initialize(*cc_other, prst)){ return retval; } - if (seteuid(eff_uid) < 0) {return errno; } - if (setegid(eff_gid) < 0) {return errno; } - - retval = krb5_store_some_creds(* cc_other, cc_def_creds_arr, cc_other_creds_arr, prst, stored); @@ -700,10 +675,11 @@ krb5_error_code retval=0; krb5_principal temp_principal; krb5_creds ** cc_creds_arr = NULL; char * cc_name; +struct stat st_temp; cc_name = krb5_cc_get_name(cc); - if ( ! access(cc_name, F_OK)){ + if ( ! stat(cc_name, &st_temp)){ if (auth_debug) { fprintf(stderr,"Refreshing cache %s\n", cc_name); @@ -744,10 +720,11 @@ krb5_principal temp_principal; krb5_creds ** cc_creds_arr = NULL; char * cc_name; krb5_boolean stored; +struct stat st_temp; cc_name = krb5_cc_get_name(cc); - if ( ! access(cc_name, F_OK)){ + if ( ! stat(cc_name, &st_temp)){ if (auth_debug) { fprintf(stderr,"puting cache %s through a filter for -z option\n", cc_name); @@ -779,3 +756,43 @@ krb5_boolean stored; return 0; } +krb5_boolean krb5_find_princ_in_cred_list ( krb5_creds ** creds_list, + krb5_principal princ){ + +int i = 0; +krb5_boolean temp_stored = FALSE; + + if (creds_list){ + while(creds_list[i]){ + if (krb5_principal_compare( creds_list[i]->client, + princ)== TRUE){ + temp_stored = TRUE; + break; + } + + i++; + } + } + +return temp_stored; +} + +krb5_error_code krb5_find_princ_in_cache ( krb5_ccache cc, + krb5_principal princ, + krb5_boolean * found ){ +krb5_error_code retval; +krb5_creds ** creds_list = NULL; +char * cc_name; +struct stat st_temp; + + cc_name = krb5_cc_get_name(cc); + + if ( ! stat(cc_name, &st_temp)){ + if(retval = krb5_get_nonexp_tkts( cc, &creds_list)){ + return retval; + } + } + + *found = krb5_find_princ_in_cred_list(creds_list, princ); +return 0; +} diff --git a/src/clients/ksu/heuristic.c b/src/clients/ksu/heuristic.c index f6217ebca..195aa24f1 100644 --- a/src/clients/ksu/heuristic.c +++ b/src/clients/ksu/heuristic.c @@ -267,7 +267,6 @@ get_authorized_princ_names( const char *luser, char *cmd, char *** princ_list) return 0; } - void close_time(int k5users_flag, FILE * users_fp, int k5login_flag, FILE * login_fp){ @@ -390,10 +389,11 @@ krb5_error_code retval; char * client_name; krb5_boolean temp_found = FALSE; char * cc_source_name; +struct stat st_temp; cc_source_name = krb5_cc_get_name(cc); -if ( ! access(cc_source_name, F_OK)){ +if ( ! stat(cc_source_name, &st_temp)){ if (retval = find_ticket (cc, client, end_server, &temp_found)) { return retval; @@ -527,6 +527,7 @@ krb5_boolean found = FALSE; struct stat tb; int count =0; int i; +struct stat st_temp; *path_out = 0; @@ -537,7 +538,7 @@ if (options->princ){ cc_source_name = krb5_cc_get_name(cc_source); -if ( ! access(cc_source_name, F_OK)){ +if ( ! stat(cc_source_name, &st_temp)){ if (retval = krb5_cc_get_principal(cc_source, &cc_def_princ)){ return retval; } @@ -574,6 +575,19 @@ if (source_uid == 0){ /* from here on, the code is for source_uid != 0 */ +if (source_uid && (source_uid == target_uid)){ + if(cc_def_princ){ + *client = cc_def_princ; + }else{ + *client = target_client; + } + if (auth_debug){ + printf("GET_best_princ_for_target: via source_uid == target_uid\n"); + } + + return 0; +} + /* if .k5users and .k5login do not exist */ if ( stat(k5login_path, &tb) && stat(k5users_path, &tb) ){ *client = target_client; @@ -682,65 +696,56 @@ while (aplist[i]){ for password promting */ -if (princ_trials[0].found == TRUE){ - *client = princ_trials[0].p; +for (i=0; i < count; i ++){ + if (princ_trials[i].found == TRUE){ + *client = princ_trials[i].p; - if (auth_debug){ - printf( - "GET_best_princ_for_target: via prompt passwd list choice: default cache principal\n"); + if (auth_debug){ + printf( + "GET_best_princ_for_target: via prompt passwd list choice #%d \n",i); + } + return 0; } - return 0; } - #ifdef PRINC_LOOK_AHEAD -if (princ_trials[0].p){ - if (retval= krb5_copy_principal(princ_trials[0].p, &temp_client)){ - return retval; - } - /* get the client name that is the closest - to default principal of source cache */ +for (i=0; i < count; i ++){ + if (princ_trials[i].p){ + if(retval=krb5_copy_principal(princ_trials[i].p, &temp_client)){ + return retval; + } - if (retval = get_closest_principal(aplist, &temp_client, & found)){ - return retval; - } + /* get the client name that is the closest + to the three princ in trials */ - if (found == TRUE){ - *client = temp_client; - if (auth_debug){ - printf( - "GET_best_princ_for_target: via prompt passwd list choice: approximation of default cache principal\n"); + if(retval=get_closest_principal(aplist, &temp_client, & found)){ + return retval; } - return 0; - } -} -#endif /* PRINC_LOOK_AHEAD */ -for (i=1; i < count; i ++){ - if (princ_trials[i].found == TRUE){ - *client = princ_trials[i].p; - if (auth_debug){ - printf( - "GET_best_princ_for_target: via prompt passwd list choice #%d \n",i); + if (found == TRUE){ + *client = temp_client; + if (auth_debug){ + printf( + "GET_best_princ_for_target: via prompt passwd list choice: approximation of princ in trials # %d \n",i); + } + return 0; } - return 0; + krb5_free_principal(temp_client); } } -/* ok looks like we are out of luck, so just take the firs name - in the list and return */ -if (retval = krb5_parse_name(aplist[0], &temp_client)){ - return retval; -} +#endif /* PRINC_LOOK_AHEAD */ + + if(auth_debug){ - printf( "GET_best_princ_for_target: out of luck choice\n"); + printf( "GET_best_princ_for_target: out of luck, can't get appropriate default principal\n"); } -*client = temp_client; +*path_out = NOT_AUTHORIZED; return 0; } diff --git a/src/clients/ksu/krb_auth_su.c b/src/clients/ksu/krb_auth_su.c index 7783562af..a30479cb8 100644 --- a/src/clients/ksu/krb_auth_su.c +++ b/src/clients/ksu/krb_auth_su.c @@ -61,7 +61,7 @@ krb5_error_code retval =0; char ** k5login_plist = NULL; int got_it = 0; char * client_name; - +krb5_boolean zero_password; *path_passwd = 0; memset((char *) &tgtq, 0, sizeof(tgtq)); @@ -136,12 +136,12 @@ char * client_name; #ifdef GET_TGT_VIA_PASSWD - fprintf(stderr,"WARNING: Your password may get exposed if you are logged in remotely \n"); - fprintf(stderr," and don't have a secure channel. \n"); + fprintf(stderr,"WARNING: Your password may be exposed if you enter it here and are logged \n"); + fprintf(stderr," in remotely using an unsecure (non-encrypted) channel. \n"); /*get the ticket granting ticket, via passwd(promt for passwd)*/ if (krb5_get_tkt_via_passwd (&cc, client, tgtq.server, - options) == FALSE){ + options, & zero_password) == FALSE){ return FALSE; } *path_passwd = 1; @@ -193,7 +193,7 @@ char * client_name; krb5_free_tgt_creds(tgts); } - if (retval = krb5_verify_tkt_def(client, server, + if (retval = krb5_verify_tkt_def(client, server, &cred.keyblock, &cred.ticket, &target_tkt)){ com_err(prog_name, retval, "while verifing ticket for server"); return (FALSE); @@ -240,7 +240,7 @@ char * client_name; } - if (retval = krb5_verify_tkt_def(client, server, + if (retval = krb5_verify_tkt_def(client, server, &tgt.keyblock, &tgt.ticket, &target_tkt)){ com_err(prog_name, retval, "while verifing ticket for server"); return (FALSE); @@ -253,7 +253,9 @@ char * client_name; krb5_error_code krb5_verify_tkt_def( /* IN */ krb5_principal client, - krb5_principal server, krb5_data * scr_ticket, + krb5_principal server, + krb5_keyblock * cred_ses_key, + krb5_data * scr_ticket, /* OUT */ krb5_ticket ** clear_ticket) { @@ -262,6 +264,7 @@ krb5_keytab_entry ktentry; krb5_keyblock *tkt_key = NULL; krb5_ticket * tkt = NULL; krb5_error_code retval =0; +krb5_keyblock * tkt_ses_key; if (retval = decode_krb5_ticket(scr_ticket, &tkt)){ return retval; @@ -305,8 +308,13 @@ krb5_error_code retval =0; return(retval); } + + if (!krb5_principal_compare(client, tkt->enc_part2->client)) { - retval = KRB5KRB_AP_ERR_BADMATCH; + krb5_free_ticket(tkt); + krb5_kt_free_entry(&ktentry); + krb5_free_keyblock(tkt_key); + return KRB5KRB_AP_ERR_BADMATCH; } if (auth_debug){ @@ -316,16 +324,35 @@ krb5_error_code retval =0; dump_principal("tkt->enc_part2->client",tkt->enc_part2->client); } + tkt_ses_key = tkt->enc_part2->session; + + if (cred_ses_key->keytype != tkt_ses_key->keytype || + cred_ses_key->length != tkt_ses_key->length || + memcmp((char *)cred_ses_key->contents, + (char *)tkt_ses_key->contents, cred_ses_key->length)) { + + krb5_free_ticket(tkt); + krb5_kt_free_entry(&ktentry); + krb5_free_keyblock(tkt_key); + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + + if (auth_debug){ + fprintf(stderr, + "krb5_verify_tkt_def: session keys match \n"); + } + *clear_ticket = tkt; krb5_kt_free_entry(&ktentry); krb5_free_keyblock(tkt_key); - return retval; + return 0; } krb5_boolean krb5_get_tkt_via_passwd (krb5_ccache * ccache, krb5_principal client, - krb5_principal server, opt_info * options) { + krb5_principal server, opt_info * options, + krb5_boolean * zero_password) { krb5_address **my_addresses; krb5_error_code code; krb5_creds my_creds; @@ -335,6 +362,9 @@ krb5_boolean krb5_get_tkt_via_passwd (krb5_ccache * ccache, krb5_principal clien int i; char password[255], *client_name, prompt[255]; + + *zero_password = FALSE; + if (code = krb5_unparse_name(client, &client_name)) { com_err (prog_name, code, "when unparsing name"); return (FALSE); @@ -379,14 +409,22 @@ krb5_boolean krb5_get_tkt_via_passwd (krb5_ccache * ccache, krb5_principal clien pwsize = sizeof(password); code = krb5_read_password(prompt, 0, password, &pwsize); - if (code || pwsize == 0) { - fprintf(stderr, "Error while reading password for '%s'\n", + if (code ) { + com_err(prog_name, code, "while reading password for '%s'\n", client_name); memset(password, 0, sizeof(password)); krb5_free_addresses(my_addresses); return (FALSE); } + if ( pwsize == 0) { + fprintf(stderr, "No password given\n"); + *zero_password = TRUE; + memset(password, 0, sizeof(password)); + krb5_free_addresses(my_addresses); + return (FALSE); + } + if (preauth_type > 0) { code = krb5_get_in_tkt_with_password(options->opt, my_addresses, preauth_type, diff --git a/src/clients/ksu/ksu.M b/src/clients/ksu/ksu.M new file mode 100644 index 000000000..704d43116 --- /dev/null +++ b/src/clients/ksu/ksu.M @@ -0,0 +1,505 @@ +.\" Copyright (c) 1994 by the University of Southern California +.\" +.\" EXPORT OF THIS SOFTWARE from the United States of America may +.\" require a specific license from the United States Government. +.\" It is the responsibility of any person or organization contemplating +.\" export to obtain such a license before exporting. +.\" +.\" WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute +.\" this software and its documentation in source and binary forms is +.\" hereby granted, provided that any documentation or other materials +.\" related to such distribution or use acknowledge that the software +.\" was developed by the University of Southern California. +.\" +.\" DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The +.\" University of Southern California MAKES NO REPRESENTATIONS OR +.\" WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not +.\" limitation, the University of Southern California MAKES NO +.\" REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY +.\" PARTICULAR PURPOSE. The University of Southern +.\" California shall not be held liable for any liability nor for any +.\" direct, indirect, or consequential damages with respect to any +.\" claim by the user or distributor of the ksu software. +.\" +.\" KSU was writen by: Ari Medvinsky, ari@isi.edu +.TH KSU 1 "Kerberos Version 5.4" +.SH NAME +ksu \- Kerberized super-user +.SH SYNOPSIS +.B ksu +[ +.I target_user +] [ +.B \-n +.I target_principal_name +] [ +.B \-c +.I source_cache_name +] [ +.B \-C +.I target_cache_name +] [ +.B \-k +] [ +.B \-D +] [ +.B \-r +.I time +] [ +.B \-pf +] [ +.B \-l +.I lifetime +] [ +.B \-zZ +] [ +.B \-q +] [ +.B \-e +.I command +[ +.I args ... +] ] [ +.B \-a +[ +.I args ... +] ] +.br +.SH REQUIREMENTS +Must have Kerberos version 5 installed to compile ksu. +Must have a Kerberos version 5 server running to use ksu. +.br +.SH DESCRIPTION +.I ksu +is a Kerberized version of the su program that has two missions: +one is to securely change the real and effective user ID to that +of the target user, the other is to create a new security context. +For the sake of clarity all references to, and attributes of +the user invoking the program will start with 'source' (e.g. +source user, source cache, etc.). Likewise all references +to and attributes of the target account, will start with 'target'. +.br +.SH AUTHENTICATION +To fulfill the first mission, ksu operates in two phases: authentication +and authorization. Resolving the target principal name is the +first step in authentication. The user +can either specify his principal name with the +.B \-n +option +(e.g. +.B \-n +jqpublic@USC.EDU) or a default principal name will be assigned +using a heuristic described in the OPTIONS section (see +.B \-n +option). +The target user name must be the first argument to ksu, if not specified +root is the default. If '.' is specified then the target user will be +the source user (e.g. ksu .). +If the source user is root or the target user is the source user, no +authentication or authorization takes place. Otherwise, ksu looks +for an appropriate Kerberos ticket in the source cache. +.PP +The ticket can either be for +the end-server +or a ticket granting ticket (TGT) for the target principal's realm. If the +ticket for the end server is already in the cache, it's, decrypted and +verified. If it's not in the cache but the TGT is, TGT is used to +obtain the ticket for the end-server. The end-server ticket is then +verified. If neither ticket is in the cache, but ksu is compiled +with the GET_TGT_VIA_PASSWD define, the user will be prompted +for a Kerberos password which will then be used to get a TGT. +If the user is logged in remotely and +does not have a secure channel, the password may be exposed. +If neither ticket is in the cache and GET_TGT_VIA_PASSWD is not defined, +authentication fails. +.br +.SH AUTHORIZATION +This section describes authorization of the source user when ksu +is invoked without the +.B \-e +option. +For a description of the +.B \-e +option, see the OPTIONS section. +.PP +Upon successful authentication, ksu checks whether the target principal +is authorized to access the target account. +In the target user's home directory, ksu attempts to access +two authorization files: .k5login and .k5users. In the .k5login +file each line contains the name of a +principal that is authorized to access the account. +.TP 12 +For example: +jqpublic@USC.EDU +.br +jqpublic/secure@USC.EDU +.br +jqpublic/admin@USC.EDU +.PP +The format of .k5users is the same, accept the +principal name may be followed by a list of commands that +the principal is authorized to execute. (see the +.B \-e +option in the OPTIONS section for details). +.PP +Thus if the target principal +name is found in the .k5login file the source user is authorized to access +the target account. Otherwise ksu looks in the .k5users file. +If the target principal name is found without any trailing commands +or followed only by '*' then the source user is authorized. +If either .k5login or .k5users exist but an appropriate entry for the target +principal does not exist then access is denied. If neither +file exists then a database of local principal names is +consulted (the name of this database is defined in Kerberos osconf.h +file by DEFAULT_LNAME_FILENAME macro). If the target principal name is +found then the source user is authorized to access the account. +If it's not found, and ksu was compiled with LOCAL_REALM macro undefined, +authorization fails. If LOCAL_REALM is defined, and it matches +the target principal's realm and the first component of the +target principal name translates to the target account name then +authorization is successful. Otherwise, authorization fails. +.br +.SH EXECUTION OF THE TARGET SHELL +Upon successful authentication and authorization, ksu +proceeds in a similar fashion to su. The environment +is unmodified with the exception of USER, HOME and SHELL variables. +If the target user is not root, USER gets set to the target user +name. Otherwise USER remains unchanged. Both HOME and SHELL are +set to the target login's default values. +In addition, the environment variable KRB5CCNAME gets set to the +name of the target cache. +The real and effective user ID are changed to that of the +target user. The target user's shell is then invoked +(the shell name is specified in the password file). +Upon termination of the shell, ksu deletes the target cache (unless +ksu is invoked with +.B \-k + or ' +.B \-C .' options). +This is implemented by first doing a fork and then an exec, instead +of just exec, as done by su. +.br +.SH CREATING A NEW SECURITY CONTEXT +.PP +Ksu can be used to create a new security context for the +target program (either the target +shell, or command specified via the -e option). +The target program inherits a set +of credentials from the source user. +By default, this set includes all of the credentials +in the source cache plus any +additional credentials obtained during authentication. +The source user is able to limit the credentials in this set +by using -z or -Z option. +-z restricts the copy of tickets from the source cache +to the target cache to only the tickets where client == +the target principal name. The -Z option +provides the target user with a fresh target cache +(no creds in the cache). Note that for security reasons, +when the source user is root and target user is non-root, +-z option is the default mode of operation. + +While no authentication takes place if the source user +is root or is the same as the target user, additional +tickets can still be obtained for the target cache. +If -n is specified and no credentials can be copied to the target +cache, the source user is prompted for a Kerberos password +(unless -Z specified or GET_TGT_VIA_PASSWD is undefined). If +successful, a TGT is obtained from the Kerberos server and +stored in the target cache. Otherwise, +if a password is not provided (user hit return) +ksu continues in a +normal mode of operation (the target cache will +not contain the desired TGT). +If the wrong password is typed in, ksu fails. +.PP +\fISide Note:\fP during authentication, only the tickets that could be +obtained without providing a password are cached in +in the source cache. +.SH OPTIONS +.TP 10 +\fB\-n \fItarget_principal_name +Specify a Kerberos target principal name. +Used in authentication and authorization +phases of ksu. + +If ksu is invoked without +.B \-n, +a default principal name is +assigned via the following heuristic: + +\fICase 1:\fP source user is non-root. +.br +If the target user is the source user the default principal name +is set to the default principal of the source cache. If the +cache does not exist then the default principal name is set to +target_user@local_realm. +If the source and target users are different and +neither ~/target_user/.k5users +nor ~/target_user/.k5login exist then +the default principal name is +target_user_login_name@local_realm. Otherwise, +starting with the first principal listed below, +ksu checks if the principal is authorized +to access the target account and whether +there is a legitimate ticket for that principal +in the source cache. If both conditions are met +that principal becomes the default target principal, +otherwise go to the next principal. + +a) default principal of the source cache +.br +b) target_user@local_realm +.br +c) source_user@local_realm + +If a-c fails try any principal for which there is +a ticket in the source cache and that is +authorized to access the target account. +If that fails select the first principal that +is authorized to access the target account from +the above list. +If none are authorized and ksu is configured with PRINC_LOOK_AHEAD +turned on, select the default principal as follows: + +For each candidate in the above list, +select an authorized principal that has +the same realm name and first part +of the principal name equal to the prefix of the candidate. +For example if candidate a) is jqpublic@ISI.EDU and jqpublic/secure@ISI.EDU +is authorized to access the target account then the default principal +is set to jqpublic/secure@ISI.EDU. + +\fICase 2:\fP source user is root. +.br +If the target user is non-root then the +default principal name is target_user@local_realm. +Else, if the source cache exists the default +principal name is set to the default principal +of the source cache. If the source cache does not +exist, default principal name is set to +root@local_realm. +.TP 10 +\fB\-c \fIsource_cache_name +Specify source cache name (e.g. +.B \-c +FILE:/tmp/my_cache). +If +.B \-c +option is not used then the +name is obtained from KRB5CCNAME environment variable. +If KRB5CCNAME is not defined the source cache name +is set to krb5cc_. +.TP 10 +\fB\-C \fItarget_cache_name +Specify the target cache name (e.g. +.B \-C +FILE:/tmp/target_cache). +If '.' is specified (e.g. ksu +\-C .) ksu uses the source +cache and does not create a new target cache. Note: +this case requires both source and target user +to have read and write permissions for the source cache. +If +.B \-C +option is not used, the default target cache name is +set to krb5cc_.(gen_sym()), +where gen_sym generates a new number such that +the resulting cache does not already exist. +.br +For example: krb5cc_1984.2 +.TP 10 +\fB\-k +Do not delete the target cache upon termination of the +target shell or a command ( +.B \-e +command). +Without +.B \-k, +ksu deletes the target cache +(unless ksu was invoked with '-C .' option). +.TP 10 +\fB\-D +turn on debug mode. +.TP 10 +\fITicket granting ticket options: -l lifetime -r time -pf\fP +The ticket granting ticket options only apply to the +case where there are no appropriate tickets in +the cache to authenticate the source user. In this case +if ksu is configured to prompt users for a +Kerberos password (GET_TGT_VIA_PASSWD is defined), +the ticket granting +ticket options that are specified will be used +when getting a ticket granting ticket from the Kerberos +server. +.TP 10 +\fB\-l \fIlifetime +option specifies the lifetime to be +requested for the ticket; if this option is not +specified, the default ticket lifetime +(configured by each site) is used instead. +.TP 10 +\fB\-r \fItime +option specifies that the RENEWABLE option +should be requested for the ticket, and specifies +the desired total lifetime of the ticket. +.TP 10 +\fB\-p +option specifies that the PROXIABLE option should be +requested for the ticket. +.TP 10 +\fB\-f +option specifies that the FORWARDABLE option should +be requested for the ticket. +.TP 10 +\fB\-z +restrict the copy of tickets from the source cache +to the target cache to only the tickets where client == +the target principal name. Use the +.B \-n +option +if you want the tickets for other then the default +principal. Note that the +.B \-z +option is mutually +exclusive with '-C .' and -Z options. +.TP 10 +\fB\-Z +Don't copy any tickets from the source cache to the +target cache. Just create a fresh target cache, +where the default principal name of the cache is +initialized to the target principal name. Note that +.B \-Z +option is mutually +exclusive with '-C .' and -z options. +.TP 10 +\fB\-q +suppress the printing of status messages. +.TP 10 +\fB\-e \fIcommand [args ...] +ksu proceeds exactly the same as if it was invoked without the +.B \-e +option, +except instead of executing the target shell, ksu executes the +specified command (Example of usage: ksu bob +.B \-e +ls +.B \-lag). + +\fIThe authorization algorithm for -e is as follows:\fP + +If the source user is root or source user == target user, +no authorization takes place and +the command is executed. If source user id != 0, and .k5users +file does not exist, authorization fails. +Otherwise, .k5users file must have an +appropriate entry for target principal +to get authorized. + +\fIThe .k5users file format:\fP + +A single principal entry on each line +that may be followed by a list of commands that +the principal is authorized to execute. +A principal name followed by a '*' means +that the user is authorized to execute +any command. Thus, in the following example: + +jqpublic@USC.EDU ls mail /local/kerberos/klist +.br +jqpublic/secure@USC.EDU * +.br +jqpublic/admin@USC.EDU + +jqpublic@USC.EDU is only authorized to execute ls, mail +and klist commands. jqpublic/secure@USC.EDU is authorized +to execute any command. jqpublic/admin@USC.EDU is not +authorized to execute any command. Note, that +jqpublic/admin@USC.EDU is authorized to execute +the target shell (regular ksu, without the +.B \-e +option) but jqpublic@USC.EDU is not. + +The commands listed after the principal name must +be either a full path names or just the program name. +In the second case, CMD_PATH specifying the location +of authorized programs must be defined at the +compilation time of ksu. + +\fIWhich command gets executed ?\fP + +If the source user is root or +the target user is the source user or +the user +is authorized to execute any command ('*' entry) +then command can be either a full or a relative +path leading to the target program. +Otherwise, the user must specify either a full +path or just the program name. +.TP 10 +\fB\-a \fIargs +specify arguments to be passed to the target shell. +Note: that all flags and parameters following -a +will be passed to the shell, thus all options +intended for ksu must precede +.B \-a. +.B \-a +option can be used to simulate the +.B \-e +option if used as follows: +.B \-a +.B \-c +[command [arguments]]. +.B \-c +is interpreted by the c-shell to execute the command. +.PP +.SH INSTALLATION INSTRUCTIONS +ksu can be compiled with the following 5 flags (see the Imakefile): +.TP 10 +\fILOCAL_REALM\fP +possible values: the name of the local realm +or '.' in which case krb.conf is used to look +up the local realm name. +.TP 10 +\fIGET_TGT_VIA_PASSWD\fP +in case no appropriate tickets are found in the source +cache, the user will be prompted for a Kerberos +password. The password is then used to get a +ticket granting ticket from the Kerberos server. +The danger of configuring ksu with this macro is +if the source user is loged in remotely and does not +have a secure channel, the password may get exposed. +.TP 10 +\fIPRINC_LOOK_AHEAD\fP +during the resolution of the default principal name, +PRINC_LOOK_AHEAD enables ksu to find principal names +in the .k5users file as described in the OPTIONS section +(see -n option). +.TP 10 +\fICMD_PATH\fP +specifies a list of directories containing programs +that users are authorized to execute (via .k5users file). +.TP 10 +\fIHAS_GETUSERSHELL\fP +If the source user is non-root, ksu insists that +the target user's shell to be invoked +is a "legal shell". getusershell(3) is called to obtain +the names of "legal shells". Note that the target user's +shell is obtained from the passwd file. +.TP 10 +SAMPLE CONFIGURATION: +KSU_OPTS = -DLOCAL_REALM='"ISI.EDU"' -DGET_TGT_VIA_PASSWD +-DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /usr/ucb /local/bin" +.TP 10 +PERMISSIONS FOR KSU +ksu should be owned by root and have the set user id bit turned on. +.TP 10 +END-SERVER ENTRY +ksu attempts to get a ticket for the end server just as +Kerberized telnet and rlogin. Thus, there must be +an entry for the server in the Kerberos database +(e.g. host/nii.isi.edu@ISI.EDU). k5srvtab must be in +an appropriate location. +.SH SIDE EFFECTS +ksu deletes all expired tickets from the source cache. +.SH AUTHOR OF KSU: GENNADY (ARI) MEDVINSKY diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h index ed31dc278..a8d968574 100644 --- a/src/clients/ksu/ksu.h +++ b/src/clients/ksu/ksu.h @@ -41,11 +41,13 @@ #include #include #include +#include #define NO_TARGET_FILE '.' +#define SOURCE_USER_LOGIN "." #define KRB5_DEFAULT_OPTIONS 0 -#define KRB5_DEFAULT_TKT_LIFE 60*60*8 /* 8 hours */ +#define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */ #define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_" @@ -68,6 +70,7 @@ extern char * optarg; /* globals */ extern char * prog_name; extern int auth_debug; +extern int quiet; extern char k5login_path[MAXPATHLEN]; extern char k5users_path[MAXPATHLEN]; extern char * gb_err; @@ -86,7 +89,7 @@ extern void dump_principal (); extern krb5_error_code krb5_verify_tkt_def(); extern krb5_boolean krb5_fast_auth(); extern krb5_boolean krb5_get_tkt_via_passwd (); -extern int gen_sim(); +extern int gen_sym(); extern krb5_error_code krb5_authorization(); extern krb5_error_code k5login_lookup (); extern krb5_error_code k5users_lookup (); @@ -94,6 +97,8 @@ extern krb5_error_code get_line (); extern char * get_first_token (); extern char * get_next_token (); extern krb5_boolean fowner(); +extern krb5_boolean krb5_find_princ_in_cred_list(); +extern krb5_error_code krb5_find_princ_in_cache(); #ifndef min #define min(a,b) ((a) > (b) ? (b) : (a)) diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c index 277c99efc..2c4ce7851 100644 --- a/src/clients/ksu/main.c +++ b/src/clients/ksu/main.c @@ -33,6 +33,7 @@ int auth_debug =0; char k5login_path[MAXPATHLEN]; char k5users_path[MAXPATHLEN]; char * gb_err = NULL; +int quiet = 0; /***********/ #define _DEF_CSH "/bin/csh" @@ -40,13 +41,15 @@ int set_env_var(); void sweep_up(); char * ontty(); void init_auth_names(); +void print_status( const char *fmt, ...); +char * get_dir_of_file(); /* Note -e and -a options are mutually exclusive */ /* insure the proper specification of target user as well as catching ill specified arguments to commands */ void usage (){ - fprintf(stderr, "Usage: %s [target user] [-n principal] [-c source cachename] [-C target cachename] [-k] [-D] [-r time] [-pf] [-l lifetime] [-zZ] [-e command [args... ] ] [-a [args... ] ] \n", prog_name); + fprintf(stderr, "Usage: %s [target user] [-n principal] [-c source cachename] [-C target cachename] [-k] [-D] [-r time] [-pf] [-l lifetime] [-zZ] [-q] [-e command [args... ] ] [-a [args... ] ] \n", prog_name); } @@ -96,6 +99,11 @@ int pargc; char ** pargv; struct stat st_temp; int temp_debug; +krb5_boolean stored = FALSE; +krb5_principal kdc_server; +krb5_boolean zero_password; +char * dir_of_cc_target; +char * dir_of_cc_source; options.opt = KRB5_DEFAULT_OPTIONS; options.lifetime = KRB5_DEFAULT_TKT_LIFE; @@ -151,7 +159,7 @@ int temp_debug; } - while(!done && ((option = getopt(pargc, pargv,"n:c:C:r:a:zZDfpkl:e:")) != EOF)){ + while(!done && ((option = getopt(pargc, pargv,"n:c:C:r:a:zZDfpkql:e:")) != EOF)){ switch (option) { case 'r': options.opt |= KDC_OPT_RENEWABLE; @@ -183,6 +191,9 @@ int temp_debug; case 'k': keep_target_cache =1; break; + case 'q': + quiet =1; + break; case 'l': retval = krb5_parse_lifetime(optarg, &options.lifetime); if (retval != 0 || options.lifetime == 0) { @@ -232,7 +243,6 @@ int temp_debug; } } else { - fprintf(stderr,"In -C option \n"); if ( strchr(cc_target_tag, ':')){ cc_target_tag_tmp=strchr(cc_target_tag,':') + 1; if(!stat(cc_target_tag_tmp, &st_temp )){ @@ -335,6 +345,11 @@ int temp_debug; source_uid = pwd->pw_uid; source_gid = pwd->pw_gid; + + if (!strcmp(SOURCE_USER_LOGIN, target_user)){ + target_user = strdup (source_user); + } + if ((target_pwd = getpwnam(target_user)) == NULL){ fprintf(stderr, "ksu: unknown login %s\n", target_user); exit(1); @@ -358,7 +373,7 @@ int temp_debug; /* get a handle for the cache */ if ( retval = krb5_cc_resolve(cc_source_tag, &cc_source)){ com_err(prog_name, retval,"while getting source cache"); - exit(0); + exit(1); } @@ -369,14 +384,14 @@ int temp_debug; fprintf(stderr, "%s does not have correct permissions for %s\n", source_user, cc_source_tag); - exit(0); + exit(1); } if (retval= krb5_ccache_refresh(cc_source)){ com_err(prog_name, retval, "while refreshing %s (source cache)", cc_source_tag); - exit(0); + exit(1); } } @@ -386,7 +401,7 @@ int temp_debug; target_user, cc_source, &options, cmd, localhostname, &client, &hp)){ com_err(prog_name, retval, "while selecting the best principal"); - exit(0); + exit(1); } if (auth_debug){ @@ -403,35 +418,34 @@ int temp_debug; if (hp){ if (gb_err) fprintf(stderr, "%s", gb_err); - fprintf(stderr, "Not authorized\n"); - exit(0); + fprintf(stderr,"account %s: authorization failed\n",target_user); + exit(1); } - if ( stat(cc_source_tag_tmp, &st_temp)){ if (use_source_cache){ - eff_uid = geteuid(); - eff_gid = getegid(); - - if (seteuid(source_uid) < 0) - { perror("ksu: seteuid"); exit(1);} + dir_of_cc_source = get_dir_of_file(cc_source_tag_tmp); - if (setegid(source_gid) < 0) - { perror("ksu: setegid"); exit(1);} + + if (access(dir_of_cc_source, R_OK | W_OK )){ + fprintf(stderr, + "%s does not have correct permissions for %s\n", + source_user, cc_source_tag); + exit(1); + } if (retval = krb5_cc_initialize(cc_source, client)){ com_err(prog_name, retval, "while initializing source cache"); - exit(0); + exit(1); + } + if (chown(cc_source_tag_tmp, source_uid, source_gid)){ + com_err(prog_name, errno, + "while changing owner for %s", + cc_source_tag_tmp); + exit(1); } - - if (seteuid(eff_uid) < 0) - { perror("ksu: seteuid"); exit(1); } - - if (setegid(eff_gid) < 0) - { perror("ksu: setegid"); exit(1); } - } } @@ -441,7 +455,7 @@ int temp_debug; cc_target_tag = (char *)calloc(KRB5_SEC_BUFFSIZE ,sizeof(char)); do { sprintf(cc_target_tag, "%s%d.%d", KRB5_SECONDARY_CACHE, - target_uid, gen_sim()); + target_uid, gen_sym()); cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1; }while ( !stat ( cc_target_tag_tmp, &st_temp)); @@ -449,15 +463,23 @@ int temp_debug; } + dir_of_cc_target = get_dir_of_file( use_source_cache ? + cc_source_tag_tmp: cc_target_tag_tmp); + + if (access(dir_of_cc_target, R_OK | W_OK )){ + fprintf(stderr, + "%s does not have correct permissions for %s\n", + source_user, cc_target_tag); + exit(1); + } + if (auth_debug){ fprintf(stderr, " source cache = %s\n", cc_source_tag); fprintf(stderr, " target cache = %s\n", cc_target_tag); } - - - /* Make sure that the resulting cache file is owned by the - source user. Only when proper authentication and authorization + /* + Only when proper authentication and authorization takes place, the target user becomes the owner of the cache. */ @@ -468,69 +490,95 @@ int temp_debug; should be copied */ if ((source_uid == 0) && (target_uid != 0)) { - krb5_principal kdc_server ; - krb5_boolean stored = FALSE; if (retval =krb5_ccache_copy_restricted( cc_source, cc_target_tag,client,&cc_target, &stored)){ com_err (prog_name, retval, "while copying cache %s to %s", krb5_cc_get_name(cc_source),cc_target_tag); - exit(0); + exit(1); } - if (retval = krb5_tgtname( krb5_princ_realm (client), - krb5_princ_realm(client), - &kdc_server)){ - com_err(prog_name, retval, - "while creating tgt for local realm") ; - sweep_up(use_source_cache, cc_target); - exit(0); - } - - -#ifdef GET_TGT_VIA_PASSWD - if ((!all_rest_copy) && options.princ && (stored == FALSE)){ - fprintf(stderr,"WARNING: Your password may get exposed if you are logged in remotely \n"); - fprintf(stderr," and don't have a secure channel. \n"); - if (krb5_get_tkt_via_passwd (&cc_target, client, - kdc_server, &options) == FALSE){ - fprintf(stderr, - "could not get a tgt for "); - plain_dump_principal (client); - fprintf(stderr, "\n"); - - } - } -#endif /* GET_TGT_VIA_PASSWD */ } else{ if (retval = krb5_ccache_copy(cc_source, cc_target_tag, - client,&cc_target)){ + client,&cc_target, &stored)){ com_err (prog_name, retval, "while copying cache %s to %s", krb5_cc_get_name(cc_source), cc_target_tag); - exit(0); + exit(1); } + } } else{ - cc_target = cc_source; cc_target_tag = cc_source_tag; cc_target_tag_tmp = cc_source_tag_tmp; + if(retval=krb5_find_princ_in_cache(cc_target,client, &stored)){ + com_err (prog_name, retval, + "while searching for client in source ccache"); + exit(1); + } + } + + if ((source_uid == 0) || (target_uid == source_uid)){ + #ifdef GET_TGT_VIA_PASSWD + if ((!all_rest_copy) && options.princ && (stored == FALSE)){ + if (retval = krb5_tgtname(krb5_princ_realm (client), + krb5_princ_realm(client), + &kdc_server)){ + com_err(prog_name, retval, + "while creating tgt for local realm"); + sweep_up(use_source_cache, cc_target); + exit(1); + } + + fprintf(stderr,"WARNING: Your password may be exposed if you enter it here and are logged \n"); + fprintf(stderr," in remotely using an unsecure (non-encrypted) channel.\n"); + if (krb5_get_tkt_via_passwd (&cc_target, client, + kdc_server, &options, + &zero_password) == FALSE){ + + if (zero_password == FALSE){ + fprintf(stderr,"Goodbye\n"); + sweep_up(use_source_cache, + cc_target); + exit(1); + } + + fprintf(stderr, + "Could not get a tgt for "); + plain_dump_principal (client); + fprintf(stderr, "\n"); + + } + } + #endif /* GET_TGT_VIA_PASSWD */ } - /* if the user is root then authentication is not neccesary, + /* if the user is root or same uid then authentication is not neccesary, root gets in automatically */ - if (source_uid) { + if (source_uid && (source_uid != target_uid)) { char * client_name; auth_val = krb5_auth_check(client, localhostname, &options, target_user,cc_target, &path_passwd); + + + /* if kerbereros authentication failed then exit */ + if (auth_val ==FALSE){ + fprintf(stderr, "Authentication failed.\n"); + syslog(LOG_WARNING, + "'%s %s' authentication failed for %s%s", + prog_name,target_user,source_user,ontty()); + sweep_up(use_source_cache, cc_target); + exit(1); + } + /* cache the tickets if possible in the source cache */ if (!path_passwd && !use_source_cache){ @@ -541,28 +589,23 @@ int temp_debug; krb5_cc_get_name(cc_target), krb5_cc_get_name(cc_source)); sweep_up(use_source_cache, cc_target); - exit(0); + exit(1); + } + if (chown(cc_source_tag_tmp, source_uid, source_gid)){ + com_err(prog_name, errno, + "while changing owner for %s", + cc_source_tag_tmp); + exit(1); } - - } - - /* if kerbereros authentication failed then exit */ - if (auth_val ==FALSE){ - fprintf(stderr, "Authentication failed.\n"); - syslog(LOG_WARNING, - "'%s %s' authentication failed for %s%s", - prog_name,target_user,source_user,ontty()); - sweep_up(use_source_cache, cc_target); - exit(0); } if (retval = krb5_unparse_name(client, &client_name)) { com_err (prog_name, retval, "When unparsing name"); sweep_up(use_source_cache, cc_target); - exit(0); + exit(1); } - fprintf(stderr,"Authenticated %s\n", client_name); + print_status("Authenticated %s\n", client_name); syslog(LOG_NOTICE,"'%s %s' authenticated %s for %s%s", prog_name,target_user,client_name, source_user,ontty()); @@ -571,22 +614,22 @@ int temp_debug; local_realm_name, cmd, &authorization_val, &exec_cmd)){ com_err(prog_name,retval,"while checking authorization"); sweep_up(use_source_cache, cc_target); - exit(0); + exit(1); } if (authorization_val == TRUE){ if (cmd) { - fprintf(stderr, + print_status( "Account %s: authorization for %s for execution of\n", target_user, client_name); - fprintf(stderr, " %s successful\n",exec_cmd); + print_status(" %s successful\n",exec_cmd); syslog(LOG_NOTICE, "Account %s: authorization for %s for execution of %s successful", target_user, client_name, exec_cmd); }else{ - fprintf(stderr, + print_status( "Account %s: authorization for %s successful\n", target_user, client_name); syslog(LOG_NOTICE, @@ -617,7 +660,7 @@ int temp_debug; } sweep_up(use_source_cache, cc_target); - exit(0); + exit(1); } } @@ -625,7 +668,7 @@ int temp_debug; if (retval = krb5_ccache_filter(cc_target, client)){ com_err(prog_name,retval,"while calling cc_filter"); sweep_up(use_source_cache, cc_target); - exit(0); + exit(1); } } @@ -633,7 +676,7 @@ int temp_debug; if (retval = krb5_cc_initialize(cc_target, client)){ com_err(prog_name, retval, "while erasing target cache"); - exit(0); + exit(1); } } @@ -647,16 +690,16 @@ int temp_debug; shell = _DEF_CSH; /* default is cshell */ } - /* insist that the target login uses a standard shell (root is omited) */ #ifdef HAS_GETUSERSHELL + + /* insist that the target login uses a standard shell (root is omited) */ + if (!standard_shell(target_pwd->pw_shell) && source_uid) { fprintf(stderr, "ksu: permission denied (shell).\n"); sweep_up(use_source_cache, cc_target); exit(1); } #endif /* HAS_GETUSERSHELL */ - - /* want to check the scoop with USER for the real ksu , MOD */ if (target_pwd->pw_uid){ @@ -681,7 +724,7 @@ int temp_debug; /* set the cc env name to target */ - if(set_env_var(KRB5_ENV_CCNAME, cc_target_tag)){ + if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){ fprintf(stderr,"ksu: couldn't set environment variable %s \n", KRB5_ENV_CCNAME); sweep_up(use_source_cache, cc_target); @@ -716,26 +759,29 @@ int temp_debug; exit(1); } - fprintf(stderr,"Changing uid to %d\n", target_pwd->pw_uid); + if ( ! strcmp(target_user, source_user)){ + print_status("Leaving uid as %s (%d)\n", + target_user, target_pwd->pw_uid); + }else{ + print_status("Changing uid to %s (%d)\n", + target_user, target_pwd->pw_uid); + } + if (setuid(target_pwd->pw_uid) < 0) { perror("ksu: setuid"); sweep_up(use_source_cache, cc_target); exit(1); } - /* verify that the target user can read and write - to the new cache */ - - if (access( cc_target_tag_tmp, R_OK | W_OK )){ - com_err(prog_name, errno, - "%s does not have correct permissions for %s, %s aborted", - target_user, cc_target_tag_tmp, prog_name); - exit(1); - } - + if (access( cc_target_tag_tmp, R_OK | W_OK )){ + com_err(prog_name, errno, + "%s does not have correct permissions for %s, %s aborted", + target_user, cc_target_tag_tmp, prog_name); + exit(1); + } if (cmd){ - if (source_uid == 0){ + if ((source_uid == 0) || (source_uid == target_uid )){ exec_cmd = cmd; } @@ -773,18 +819,24 @@ int temp_debug; exit(1); } sweep_up(use_source_cache, cc_target); + + if (auth_debug){ + printf("The exit status of the child is %d\n", + statusp); + } + + exit (statusp); }else{ execv(params[0], params); com_err(prog_name, errno, "while trying to execv %s", params[0]); - exit(1); - + exit (1); } } } - #ifdef HAS_GETUSERSHELL + int standard_shell(sh) char *sh; { @@ -796,10 +848,8 @@ char *getusershell(); return (1); return (0); } -#endif - -/* Modify this later , (clean it up) , MOD */ +#endif /* HAS_GETUSERSHELL */ char * ontty() { @@ -872,3 +922,31 @@ return 0; } +void print_status( const char *fmt, ...) +{ +va_list ap; + if (! quiet){ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + + +char * get_dir_of_file( char * path){ + +char * temp_path; +char * ptr; + +temp_path = strdup(path); + +if (ptr = strrchr( temp_path, '/')){ + *ptr = '\0'; +}else{ + free (temp_path); + temp_path = (char *) calloc(MAXPATHLEN, sizeof(char)); + temp_path = (char *) getwd(temp_path); +} + +return temp_path; +} -- 2.26.2