Included fixes submitted by Ari/Cliff, including a security fix
authorTheodore Tso <tytso@mit.edu>
Wed, 15 Jun 1994 05:00:32 +0000 (05:00 +0000)
committerTheodore Tso <tytso@mit.edu>
Wed, 15 Jun 1994 05:00:32 +0000 (05:00 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3797 dc483132-0cff-0310-8789-dd5450dbe970

src/clients/ksu/Imakefile
src/clients/ksu/ccache.c
src/clients/ksu/heuristic.c
src/clients/ksu/krb_auth_su.c
src/clients/ksu/ksu.M [new file with mode: 0644]
src/clients/ksu/ksu.h
src/clients/ksu/main.c

index d34819423ba71d2eb4ad0cfc73d90cacbfa61a6b..cce25261534ad081816eaaacfbb6aa21284c9602 100644 (file)
 # 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()
index 38410b9779282b6b32d0743d911c4e836d5fe21f..b778af87b1c8c62c34e237b2c8020a7edf57f5b2 100644 (file)
@@ -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;
+}
index f6217ebca3194b266e8ebb0908818659e81ecb02..195aa24f137f0016fdc89a1d76dd1df5c5b4fb29 100644 (file)
@@ -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;
 
 }
index 7783562af32a541ec11cf68aea1299ca4125c580..a30479cb8cbceb8131ce0d2e86ffc1c0c360e586 100644 (file)
@@ -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 (file)
index 0000000..704d431
--- /dev/null
@@ -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_<source uid>.
+.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_<target uid>.(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
index ed31dc27824fa21646faac07f75e9546232c4ef6..a8d96857498f5252b245339bf94fb18afbec5506 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <syslog.h>
+#include <stdarg.h>
 
 #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))
index 277c99efc638e8a4ea993e785446863823b4f3b5..2c4ce78511072339b9fa74a8d68797bbc6d3ca7c 100644 (file)
@@ -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;  
+}