 b42ab99857
			
		
	
	b42ab99857
	
	
	
		
			
			git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17876 ec53bebd-3082-4978-b11e-865c3cabbd6b
		
			
				
	
	
		
			793 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			793 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) Copyright 1995 HEWLETT-PACKARD COMPANY
 | |
|  * 
 | |
|  * To anyone who acknowledges that this file is provided 
 | |
|  * "AS IS" without any express or implied warranty:
 | |
|  * permission to use, copy, modify, and distribute this 
 | |
|  * file for any purpose is hereby granted without fee, 
 | |
|  * provided that the above copyright notice and this 
 | |
|  * notice appears in all copies, and that the name of 
 | |
|  * Hewlett-Packard Company not be used in advertising or 
 | |
|  * publicity pertaining to distribution of the software 
 | |
|  * without specific, written prior permission.  Hewlett-
 | |
|  * Packard Company makes no representations about the 
 | |
|  * suitability of this software for any purpose.
 | |
|  *
 | |
|  */
 | |
| /*
 | |
|  * k5dcecon - Program to convert a K5 TGT to a DCE context,
 | |
|  * for use with DFS and its PAG.
 | |
|  * 
 | |
|  * The program is designed to be called as a sub process, 
 | |
|  * and return via stdout the name of the cache which implies 
 | |
|  * the PAG which should be used. This program itself does not 
 | |
|  * use the cache or PAG itself, so the PAG in the kernel for 
 | |
|  * this program may not be set. 
 | |
|  * 
 | |
|  * The calling program can then use the name of the cache
 | |
|  * to set the KRB5CCNAME and PAG for its self and its children. 
 | |
|  *
 | |
|  * If no ticket was passed, an attemplt to join an existing
 | |
|  * PAG will be made. 
 | |
|  * 
 | |
|  * If a forwarded K5 TGT is passed in, either a new DCE 
 | |
|  * context will be created, or an existing one will be updated.
 | |
|  * If the same ticket was already used to create an existing
 | |
|  * context, it will be joined instead. 
 | |
|  * 
 | |
|  * Parts of this program are based on k5dceauth,c which was
 | |
|  * given to me by HP and by the k5dcelogin.c which I developed. 
 | |
|  * A slightly different version of k5dcelogin.c, was added to
 | |
|  * DCE 1.2.2
 | |
|  * 
 | |
|  * D. E. Engert 6/17/97 ANL
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <fcntl.h>
 | |
| #include <sys/types.h>
 | |
| #include <dirent.h>
 | |
| #include <sys/stat.h>
 | |
| #include <locale.h>
 | |
| #include <pwd.h>
 | |
| #include <string.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #include <errno.h>
 | |
| #include "k5dce.h"
 | |
| 
 | |
| #include <dce/sec_login.h>
 | |
| #include <dce/dce_error.h>
 | |
| #include <dce/passwd.h>
 | |
| 
 | |
| /* #define DEBUG */
 | |
| #if defined(DEBUG)
 | |
| #define DEEDEBUG(A) fprintf(stderr,A); fflush(stderr)
 | |
| #define DEEDEBUG2(A,B) fprintf(stderr,A,B); fflush(stderr)
 | |
| #else
 | |
| #define DEEDEBUG(A)
 | |
| #define DEEDEBUG2(A,B)
 | |
| #endif
 | |
| 
 | |
| #ifdef __hpux
 | |
| #define seteuid(A)		setresuid(-1,A,-1)
 | |
| #endif
 | |
| 
 | |
| 
 | |
| int k5dcecreate (uid_t, char *, char*, krb5_creds **);
 | |
| int k5dcecon (uid_t, char *, char *);
 | |
| int k5dcegettgt (krb5_ccache *, char *, char *, krb5_creds **);
 | |
| int k5dcematch (uid_t, char *, char *, off_t *, krb5_creds **);
 | |
| int k5dcesession (uid_t, char *, krb5_creds **, int *,krb5_flags);
 | |
| 
 | |
| 
 | |
| char *progname = "k5dcecon";
 | |
| static time_t now;
 | |
| 
 | |
| #ifdef notdef
 | |
| #ifdef _AIX
 | |
| /*---------------------------------------------*/
 | |
|  /* AIX with DCE 1.1 does not have the com_err in the libdce.a
 | |
|   * do a half hearted job of substituting for it. 
 | |
|   */ 
 | |
| void com_err(char *p1, int code, ...) 
 | |
| {
 | |
|     int lst;
 | |
|     dce_error_string_t  err_string;
 | |
|     dce_error_inq_text(code, err_string, &lst);
 | |
|     fprintf(stderr,"Error %d in %s: %s\n", code, p1, err_string );
 | |
| }
 | |
| 
 | |
| /*---------------------------------------------*/
 | |
| void krb5_init_ets()
 | |
| {
 | |
| 
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /*------------------------------------------------*/
 | |
| /* find a cache to use  for our new pag           */
 | |
| /* Since there is no simple way to determine which
 | |
|  * caches are associated with a pag, we will have
 | |
|  * do look around and see what makes most sense on 
 | |
|  * different systems. 
 | |
|  * on a Solaris system, and in the DCE source, 
 | |
|  * the pags always start with a 41. 
 | |
|  * this is not true on the IBM, where there does not
 | |
|  * appear to be any pattern. 
 | |
|  * 
 | |
|  * But since we are always certifing our creds when
 | |
|  * they are received, we can us that fact, and look
 | |
|  * at the first word of the associated data file
 | |
|  * to see that it has a "5". If not don't use. 
 | |
|  */
 | |
| 
 | |
| int k5dcesession(luid, pname, tgt, ppag, tflags)
 | |
|   uid_t luid;
 | |
|   char *pname;
 | |
|   krb5_creds **tgt;
 | |
|   int *ppag;
 | |
|   krb5_flags tflags;
 | |
| {
 | |
|   DIR *dirp;
 | |
|   struct dirent *direntp;
 | |
|   off_t size;
 | |
|   krb5_timestamp endtime;
 | |
|   int better = 0;
 | |
|   krb5_creds *xtgt;
 | |
| 
 | |
|   char prev_name[17] = "";  
 | |
|   krb5_timestamp prev_endtime;
 | |
|   off_t prev_size;
 | |
|   u_long prev_pag = 0;
 | |
| 
 | |
|   char ccname[64] = "FILE:/opt/dcelocal/var/security/creds/";
 | |
|  
 | |
|   error_status_t st;
 | |
|   sec_login_handle_t lcontext = 0;
 | |
|   dce_error_string_t  err_string;
 | |
|   int lst;
 | |
| 
 | |
|   DEEDEBUG2("k5dcesession looking for flags %8.8x\n",tflags);
 | |
| 
 | |
|   dirp = opendir("/opt/dcelocal/var/security/creds/");
 | |
|   if (dirp == NULL) {
 | |
| 	return 1;
 | |
|   }
 | |
| 
 | |
|   while ( (direntp = readdir( dirp )) != NULL ) {
 | |
| 
 | |
| /*  
 | |
|  * (but root has the ffffffff which we are not interested in)
 | |
|  */
 | |
|     if (!strncmp(direntp->d_name,"dcecred_",8)
 | |
|          && (strlen(direntp->d_name) == 16)) {
 | |
| 
 | |
|       /* looks like a cache name, lets do the stat, etc */
 | |
| 
 | |
|       strcpy(ccname+38,direntp->d_name);
 | |
|       if (!k5dcematch(luid, pname, ccname, &size, &xtgt))  {
 | |
| 
 | |
|         /* its one of our caches, see if it is better  
 | |
|          * i.e. the endtime is farther, and if the endtimes
 | |
|          * are the same, take the larger, as he who has the 
 | |
|          * most tickets wins.
 | |
|          * it must also had the same set of flags at least
 | |
|          * i.e. if the forwarded TGT is forwardable, this one must 
 | |
|          * be as well.   
 | |
|          */
 | |
| 
 | |
|         DEEDEBUG2("Cache:%s",direntp->d_name);
 | |
|         DEEDEBUG2(" size:%d",size);
 | |
| 		DEEDEBUG2(" flags:%8.8x",xtgt->ticket_flags);
 | |
| 		DEEDEBUG2(" %s",ctime((time_t *)&xtgt->times.endtime));
 | |
|  
 | |
|         if ((xtgt->ticket_flags & tflags) == tflags ) {
 | |
|           if (prev_name[0]) {
 | |
|             if (xtgt->times.endtime > prev_endtime) {
 | |
|               better = 1;
 | |
|             } else if ((xtgt->times.endtime = prev_endtime) 
 | |
|                   && (size > prev_size)){
 | |
|               better = 1;
 | |
| 	        }
 | |
|           } else {   /* the first */
 | |
|             if (xtgt->times.endtime >= now) {
 | |
|             better = 1;
 | |
| 	        }
 | |
|           }
 | |
|           if (better) {
 | |
|             strcpy(prev_name, direntp->d_name);
 | |
| 	  	    prev_endtime = xtgt->times.endtime;
 | |
|             prev_size = size;
 | |
|             sscanf(prev_name+8,"%8X",&prev_pag);
 | |
| 			*tgt = xtgt;
 | |
|             better = 0;
 | |
|           }
 | |
|         }
 | |
|       } 
 | |
|     }
 | |
|   }
 | |
|   (void)closedir( dirp );
 | |
| 
 | |
|   if (!prev_name[0])  
 | |
| 	 return 1; /* failed to find one */
 | |
| 
 | |
|    DEEDEBUG2("Best: %s\n",prev_name);
 | |
| 
 | |
|    if (ppag)
 | |
|       *ppag = prev_pag;
 | |
| 
 | |
|    strcpy(ccname+38,prev_name);
 | |
|    setenv("KRB5CCNAME",ccname,1);
 | |
|  
 | |
|    return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*----------------------------------------------*/
 | |
| /* see if this cache is for this this principal */
 | |
| 
 | |
| int k5dcematch(luid, pname, ccname, sizep, tgt) 
 | |
|   uid_t luid;
 | |
|   char *pname;
 | |
|   char *ccname;
 | |
|   off_t *sizep;  /* size of the file */
 | |
|   krb5_creds **tgt;
 | |
| {
 | |
| 
 | |
|   krb5_ccache cache;
 | |
|   struct stat stbuf;
 | |
|   char ccdata[256];
 | |
|   int fd;
 | |
|   int status;
 | |
| 
 | |
|   /* DEEDEBUG2("k5dcematch called: cache=%s\n",ccname+38); */
 | |
| 
 | |
|   if (!strncmp(ccname,"FILE:",5)) {
 | |
| 
 | |
|     strcpy(ccdata,ccname+5);
 | |
|     strcat(ccdata,".data");
 | |
| 
 | |
|     /* DEEDEBUG2("Checking the .data file for %s\n",ccdata); */
 | |
| 
 | |
|     if (stat(ccdata, &stbuf))
 | |
|       return(1);
 | |
|  
 | |
|     if (stbuf.st_uid != luid)
 | |
|       return(1);
 | |
| 
 | |
|     if ((fd = open(ccdata,O_RDONLY)) == -1)
 | |
|       return(1);
 | |
|     
 | |
|     if ((read(fd,&status,4)) != 4) {
 | |
|       close(fd);
 | |
|       return(1);
 | |
|     }
 | |
|     
 | |
|     /* DEEDEBUG2(".data file status = %d\n", status); */
 | |
| 
 | |
|     if (status != 5)
 | |
|      return(1);
 | |
| 
 | |
|     if (stat(ccname+5, &stbuf))
 | |
|       return(1);
 | |
| 
 | |
|     if (stbuf.st_uid != luid)
 | |
|       return(1);
 | |
| 
 | |
|     *sizep = stbuf.st_size;
 | |
|   }
 | |
| 
 | |
|   return(k5dcegettgt(&cache, ccname, pname, tgt));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*----------------------------------------*/
 | |
| /* k5dcegettgt - get the tgt from a cache */
 | |
| 
 | |
| int k5dcegettgt(pcache, ccname, pname, tgt)
 | |
|   krb5_ccache *pcache;
 | |
|   char *ccname;
 | |
|   char *pname;
 | |
|   krb5_creds **tgt;
 | |
| 
 | |
| {
 | |
|   krb5_ccache cache;
 | |
|   krb5_cc_cursor cur;
 | |
|   krb5_creds creds;
 | |
|   int code;
 | |
|   int found = 1;
 | |
|   krb5_principal princ;
 | |
|   char *kusername;
 | |
|   krb5_flags flags;
 | |
|   char *sname, *realm, *tgtname = NULL;
 | |
| 
 | |
|   /* Since DCE does not expose much of the Kerberos interface,
 | |
|    * we will have to use what we can. This means setting the 
 | |
|    * KRB5CCNAME for each file we want to test
 | |
|    * We will also not worry about freeing extra cache structures
 | |
|    * as this this routine is also not exposed, and this should not 
 | |
|    * effect this module. 
 | |
|    * We should also free the creds contents, but that is not exposed
 | |
|    * either. 
 | |
|    */
 | |
| 
 | |
|   setenv("KRB5CCNAME",ccname,1);
 | |
|   cache = NULL;
 | |
|   *tgt = NULL;
 | |
| 
 | |
|   if (code = krb5_cc_default(pcache)) {
 | |
|      com_err(progname, code, "while getting ccache");
 | |
|      goto return2;
 | |
|   }
 | |
| 
 | |
|   DEEDEBUG("Got cache\n");
 | |
|   flags = 0;
 | |
|   if (code = krb5_cc_set_flags(*pcache, flags)) {
 | |
|     com_err(progname, code,"While setting flags"); 
 | |
|     goto return2;
 | |
|   }
 | |
|   DEEDEBUG("Set flags\n");
 | |
|   if (code = krb5_cc_get_principal(*pcache, &princ)) {
 | |
| 	com_err(progname, code, "While getting princ");
 | |
|     goto return1;
 | |
|   }
 | |
|   DEEDEBUG("Got principal\n");
 | |
|   if (code = krb5_unparse_name(princ, &kusername)) {
 | |
|     com_err(progname, code, "While unparsing principal");
 | |
|     goto return1;
 | |
|   }
 | |
| 
 | |
|   DEEDEBUG2("Unparsed to \"%s\"\n", kusername);
 | |
|   DEEDEBUG2("pname is \"%s\"\n", pname);
 | |
|   if (strcmp(kusername, pname)) {
 | |
|    DEEDEBUG("Principals not equal\n");
 | |
|    goto return1;
 | |
|   }
 | |
|   DEEDEBUG("Principals equal\n");
 | |
| 
 | |
|   realm = strchr(pname,'@');
 | |
|   realm++;
 | |
| 
 | |
|   if ((tgtname = malloc(9 + 2 * strlen(realm))) == 0) {
 | |
|        fprintf(stderr,"Malloc failed for tgtname\n");
 | |
|        goto return1;
 | |
|   }
 | |
| 
 | |
|   strcpy(tgtname,"krbtgt/");
 | |
|   strcat(tgtname,realm);
 | |
|   strcat(tgtname,"@");
 | |
|   strcat(tgtname,realm);
 | |
|  
 | |
|   DEEDEBUG2("Getting tgt %s\n", tgtname);
 | |
|   if (code = krb5_cc_start_seq_get(*pcache, &cur)) {
 | |
|     com_err(progname, code, "while starting to retrieve tickets");
 | |
|     goto return1;
 | |
|   }
 | |
| 
 | |
|   while (!(code = krb5_cc_next_cred(*pcache, &cur, &creds))) {
 | |
|     krb5_creds *cred = &creds;
 | |
| 
 | |
|     if (code = krb5_unparse_name(cred->server, &sname)) {
 | |
|       com_err(progname, code, "while unparsing server name");
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (strncmp(sname, tgtname, strlen(tgtname)) == 0) {
 | |
|       DEEDEBUG("FOUND\n");
 | |
|       if (code = krb5_copy_creds(&creds, tgt)) {
 | |
|         com_err(progname, code, "while copying TGT");
 | |
|         goto return1;
 | |
|       }
 | |
|       found = 0;
 | |
|       break;
 | |
|     } 
 | |
|     /* we should do a krb5_free_cred_contents(creds); */
 | |
|   }
 | |
| 
 | |
|   if (code = krb5_cc_end_seq_get(*pcache, &cur)) {
 | |
|     com_err(progname, code, "while finishing retrieval"); 
 | |
|     goto return2;
 | |
|   }
 | |
| 
 | |
| return1:
 | |
|   flags = KRB5_TC_OPENCLOSE; 
 | |
|   krb5_cc_set_flags(*pcache, flags); /* force a close */
 | |
|    
 | |
| return2:
 | |
|   if (tgtname)
 | |
|     free(tgtname);
 | |
| 
 | |
|   return(found);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*------------------------------------------*/
 | |
| /* Convert a forwarded TGT to a DCE context */
 | |
| int k5dcecon(luid, luser, pname)
 | |
|   uid_t luid;
 | |
|   char *luser;
 | |
|   char *pname;
 | |
| {
 | |
| 
 | |
|   krb5_creds *ftgt = NULL;
 | |
|   krb5_creds *tgt = NULL;
 | |
|   unsigned32 dfspag;
 | |
|   boolean32 reset_passwd = 0;
 | |
|   int lst;
 | |
|   dce_error_string_t  err_string;
 | |
|   char *shell_prog;
 | |
|   krb5_ccache fcache;
 | |
|   char *ccname;
 | |
|   char *kusername;
 | |
|   char *urealm;
 | |
|   char *cp;
 | |
|   int pag;
 | |
|   int code;
 | |
|   krb5_timestamp endtime;
 | |
| 
 | |
| 
 | |
|   /* If there is no cache to be converted, we should not be here */
 | |
| 
 | |
|   if ((ccname = getenv("KRB5CCNAME")) == NULL) {
 | |
|     DEEDEBUG("No KRB5CCNAME\n");
 | |
|     return(1);
 | |
|   }
 | |
| 
 | |
|   if (k5dcegettgt(&fcache, ccname, pname, &ftgt)) {
 | |
|     fprintf(stderr, "%s: Did not find TGT\n", progname);
 | |
|     return(1);
 | |
|   }
 | |
| 
 | |
|  
 | |
|   DEEDEBUG2("flags=%x\n",ftgt->ticket_flags);
 | |
|   if (!(ftgt->ticket_flags & TKT_FLG_FORWARDABLE)){
 | |
|     fprintf(stderr,"Ticket not forwardable\n");
 | |
|     return(0); /* but OK to continue */
 | |
|   }
 | |
| 
 | |
|   setenv("KRB5CCNAME","",1);
 | |
|     
 | |
| #define TKT_ACCEPTABLE (TKT_FLG_FORWARDABLE | TKT_FLG_PROXIABLE \
 | |
|          | TKT_FLG_MAY_POSTDATE | TKT_FLG_RENEWABLE | TKT_FLG_HW_AUTH \
 | |
|          | TKT_FLG_PRE_AUTH)
 | |
| 
 | |
|   if (!k5dcesession(luid, pname, &tgt, &pag, 
 | |
|         (ftgt->ticket_flags & TKT_ACCEPTABLE))) {
 | |
|     if (ftgt->times.endtime > tgt->times.endtime) {
 | |
|       DEEDEBUG("Updating existing cache\n"); 
 | |
|       return(k5dceupdate(&ftgt, pag));
 | |
|     } else {
 | |
|       DEEDEBUG("Using existing cache\n");
 | |
|       return(0); /* use the original one */
 | |
|     }
 | |
|   } 
 | |
|     /* see if the tgts match up */
 | |
| 
 | |
|   if ((code = k5dcecreate(luid, luser, pname, &ftgt))) {
 | |
| 	return (code);
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|    * Destroy the Kerberos5 cred cache file.
 | |
|    * but dont care aout the return code. 
 | |
|    */
 | |
| 
 | |
|   DEEDEBUG("Destroying the old cache\n");
 | |
|   if ((code = krb5_cc_destroy(fcache))) {
 | |
|     com_err(progname, code, "while destroying Kerberos5 ccache");
 | |
|   }
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*--------------------------------------------------*/
 | |
| /* k5dceupdate - update the cache with a new TGT    */
 | |
| /* Assumed that the KRB5CCNAME has been set         */
 | |
| 
 | |
| int k5dceupdate(krbtgt, pag) 
 | |
|    krb5_creds **krbtgt;
 | |
|    int pag;
 | |
| {
 | |
|  
 | |
|   krb5_ccache ccache;
 | |
|   int code;
 | |
| 
 | |
|   if (code = krb5_cc_default(&ccache)) {
 | |
|     com_err(progname, code, "while opening cache for update");
 | |
|     return(2);
 | |
|    }
 | |
| 
 | |
|   if (code = ccache->ops->init(ccache,(*krbtgt)->client)) {
 | |
|     com_err(progname, code, "while reinitilizing cache");
 | |
|     return(3);
 | |
|   } 
 | |
| 
 | |
|     /* krb5_cc_store_cred */
 | |
|   if (code = ccache->ops->store(ccache, *krbtgt)) {
 | |
|     com_err(progname, code, "while updating cache");
 | |
|     return(2);
 | |
|   }
 | |
| 
 | |
|   sec_login_pag_new_tgt(pag, (*krbtgt)->times.endtime);
 | |
|   return(0);
 | |
| }
 | |
| /*--------------------------------------------------*/
 | |
| /* k5dcecreate - create a new DCE context           */
 | |
| 
 | |
| int k5dcecreate(luid, luser, pname, krbtgt)
 | |
|    uid_t luid;
 | |
|    char *luser;
 | |
|    char *pname;
 | |
|    krb5_creds **krbtgt;
 | |
| {
 | |
|    
 | |
|     char *cp;
 | |
|     char *urealm;
 | |
|     char *username;
 | |
|     char *defrealm;
 | |
|     uid_t uid;
 | |
| 
 | |
|     error_status_t st;
 | |
|     sec_login_handle_t lcontext = 0;
 | |
|     sec_login_auth_src_t auth_src = 0;
 | |
|     boolean32 reset_passwd = 0;
 | |
|     int lst;
 | |
|     dce_error_string_t  err_string;
 | |
| 
 | |
| 	setenv("KRB5CCNAME","",1); /* make sure it not misused */
 | |
| 
 | |
| 	uid = getuid();
 | |
| 	DEEDEBUG2("uid=%d\n",uid);
 | |
|     
 | |
| 	/* if run as root, change to user, so as to have the
 | |
| 	 * cache created for the local user even if cross-cell
 | |
| 	 * If run as a user, let standard file protection work.
 | |
| 	 */
 | |
| 
 | |
| 	if (uid == 0) {
 | |
| 		if (seteuid(luid) < 0)
 | |
| 			goto abort;
 | |
| 	}  
 | |
| 
 | |
| 	cp = strchr(pname,'@');
 | |
| 	*cp = '\0';
 | |
| 	urealm = ++cp;
 | |
| 
 | |
|  DEEDEBUG2("basename=%s\n",cp);
 | |
|  DEEDEBUG2("realm=%s\n",urealm);
 | |
| 
 | |
|     /* now build the username as a single string or a /.../cell/user
 | |
|      * if this is a cross cell
 | |
|      */
 | |
| 
 | |
| 	if ((username = malloc(7+strlen(pname)+strlen(urealm))) == 0) {
 | |
|          fprintf(stderr,"Malloc failed for username\n");
 | |
|          goto abort;
 | |
|     }
 | |
|     if (krb5_get_default_realm(&defrealm)) {
 | |
|         DEEDEBUG("krb5_get_default_realm failed\n");
 | |
|         goto abort;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if (!strcmp(urealm,defrealm)) {
 | |
|         strcpy(username,pname);
 | |
|     } else {
 | |
|         strcpy(username,"/.../");
 | |
|         strcat(username,urealm);
 | |
|         strcat(username,"/");
 | |
|         strcat(username,pname);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Setup a DCE login context
 | |
|      */
 | |
| 
 | |
|     if (sec_login_setup_identity((unsigned_char_p_t)username, 
 | |
| 				 (sec_login_external_tgt|sec_login_proxy_cred),
 | |
| 				 &lcontext, &st)) {
 | |
| 	/*
 | |
| 	 * Add our TGT.
 | |
| 	 */
 | |
| 	  DEEDEBUG("Adding our new TGT\n");
 | |
| 	  sec_login_krb5_add_cred(lcontext, *krbtgt, &st);
 | |
| 	  if (st) {
 | |
| 	    dce_error_inq_text(st, err_string, &lst);
 | |
| 	    fprintf(stderr,
 | |
| 				"Error while adding credentials for %s because %s\n", 
 | |
| 				username, err_string);
 | |
| 	    goto abort;
 | |
| 	  }	
 | |
| 	  DEEDEBUG("validating and certifying\n");
 | |
| 	  /*
 | |
| 	   * Now "validate" and certify the identity,
 | |
| 	   *  usually we would pass a password here, but...
 | |
| 	   * sec_login_valid_and_cert_ident
 | |
| 	   * sec_login_validate_identity
 | |
| 	   */
 | |
| 
 | |
| 	  if (sec_login_validate_identity(lcontext, 0, &reset_passwd,
 | |
| 		 &auth_src, &st)) {
 | |
| 	    DEEDEBUG2("validate_identity st=%d\n",st);
 | |
| 	    if (st) {
 | |
| 		  dce_error_inq_text(st, err_string, &lst);
 | |
| 		  fprintf(stderr, "Validation error for %s because %s\n",
 | |
| 				 username, err_string);
 | |
| 		  goto abort;
 | |
| 	    }
 | |
| 		if (!sec_login_certify_identity(lcontext,&st)) {
 | |
| 			dce_error_inq_text(st, err_string, &lst);
 | |
| 			fprintf(stderr,
 | |
| 			"Credentials not certified because %s\n",err_string);
 | |
| 		}
 | |
| 	    if (reset_passwd) {
 | |
| 		 fprintf(stderr,
 | |
|                 "Password must be changed for %s\n", username);
 | |
| 	    }
 | |
| 	    if (auth_src == sec_login_auth_src_local) {
 | |
| 		fprintf(stderr,
 | |
| 			 "Credentials obtained from local registry for %s\n", 
 | |
| 			 username);
 | |
| 	    }
 | |
| 	    if (auth_src == sec_login_auth_src_overridden) {
 | |
| 		  fprintf(stderr, "Validated %s from local override entry, no network credentials obtained\n", username);
 | |
| 		  goto abort; 
 | |
| 
 | |
| 	    }
 | |
| 	    /*
 | |
| 	     * Actually create the cred files.
 | |
| 	     */
 | |
| 		DEEDEBUG("Ceating new cred files.\n");
 | |
| 	    sec_login_set_context(lcontext, &st);
 | |
| 	    if (st) {
 | |
| 		  dce_error_inq_text(st, err_string, &lst);
 | |
| 		  fprintf(stderr, 
 | |
|                 "Unable to set context for %s because %s\n",
 | |
| 		    username, err_string);
 | |
| 		  goto abort;
 | |
| 	    }
 | |
| 
 | |
|         /*
 | |
|          * Now free up the local context and leave the 
 | |
|          * network context with its pag
 | |
|          */
 | |
| #if 0
 | |
|         sec_login_release_context(&lcontext, &st);
 | |
|         if (st) {
 | |
|           dce_error_inq_text(st, err_string, &lst);
 | |
|           fprintf(stderr,
 | |
|                "Unable to release context for %s because %s\n",
 | |
|             username, err_string);
 | |
|           goto abort;
 | |
|         }
 | |
| #endif
 | |
| 	}
 | |
| 	else {
 | |
| 	  DEEDEBUG2("validate failed %d\n",st);
 | |
| 	  dce_error_inq_text(st, err_string, &lst);
 | |
| 	  fprintf(stderr,
 | |
|              "Unable to validate %s because %s\n", username, 
 | |
| 			err_string);
 | |
| 	  goto abort;
 | |
| 	}
 | |
|   }
 | |
|   else {
 | |
| 	dce_error_inq_text(st, err_string, &lst);
 | |
| 	fprintf(stderr, 
 | |
|           "Unable to setup login entry for %s because %s\n",
 | |
|        username, err_string);
 | |
| 	  goto abort;
 | |
|   }
 | |
| 
 | |
|  done:
 | |
|     /* if we were root, get back to root */
 | |
| 
 | |
|     DEEDEBUG2("sec_login_inq_pag %8.8x\n",
 | |
|              sec_login_inq_pag(lcontext, &st));
 | |
| 
 | |
|     if (uid == 0) {
 | |
|       seteuid(0);
 | |
|     }  
 | |
| 
 | |
| 	DEEDEBUG("completed\n");
 | |
| 	return(0);
 | |
| 
 | |
|  abort:
 | |
|     if (uid == 0) {
 | |
|       seteuid(0);
 | |
|     }  
 | |
| 
 | |
|     DEEDEBUG("Aborting\n");
 | |
|     return(2);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*-------------------------------------------------*/
 | |
| main(argc, argv)
 | |
|   int argc;
 | |
|   char *argv[];
 | |
| {
 | |
|   int status;
 | |
|   extern int optind;
 | |
|   extern char *optarg;
 | |
|   int rv;
 | |
| 
 | |
|   char *lusername = NULL;
 | |
|   char *pname = NULL;
 | |
|   int fflag = 0;
 | |
|   struct passwd *pw;
 | |
|   uid_t luid;
 | |
|   uid_t myuid;
 | |
|   char *ccname;
 | |
|   krb5_creds *tgt = NULL;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   close(2);
 | |
|   open("/tmp/k5dce.debug",O_WRONLY|O_CREAT|O_APPEND, 0600);
 | |
| #endif
 | |
| 
 | |
|   if (myuid = getuid()) {
 | |
|     DEEDEBUG2("UID = %d\n",myuid);
 | |
|     exit(33); /* must be root to run this, get out now */
 | |
|   }
 | |
| 
 | |
|   while ((rv = getopt(argc,argv,"l:p:fs")) != -1) {
 | |
|     DEEDEBUG2("Arg = %c\n", rv);
 | |
|     switch(rv) {
 | |
|       case 'l':         /* user name */
 | |
| 	lusername = optarg;
 | |
| 	DEEDEBUG2("Optarg = %s\n", optarg);
 | |
| 	break;
 | |
|       case 'p':         /* principal name */
 | |
|         pname = optarg; 
 | |
| 	DEEDEBUG2("Optarg = %s\n", optarg);
 | |
|         break;
 | |
|       case 'f':         /* convert a forwarded TGT to a context */
 | |
|         fflag++;
 | |
|         break;
 | |
|       case 's':      /* old test parameter, ignore it */
 | |
|         break; 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   setlocale(LC_ALL, "");
 | |
|   krb5_init_ets();
 | |
|   time(&now); /* set time to check expired tickets */
 | |
| 
 | |
|   /* if lusername == NULL, Then user is passed as the USER= variable */ 
 | |
| 
 | |
|   if (!lusername) {
 | |
|     lusername = getenv("USER");
 | |
|     if (!lusername) {
 | |
|       fprintf(stderr, "USER not in environment\n");
 | |
|       return(3);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((pw = getpwnam(lusername)) == NULL) {
 | |
|     fprintf(stderr, "Who are you?\n");
 | |
|     return(44);
 | |
|   }
 | |
| 
 | |
|   luid = pw->pw_uid;
 | |
| 
 | |
|   if (fflag) {  
 | |
|     status = k5dcecon(luid, lusername, pname); 
 | |
|   } else {
 | |
|     status = k5dcesession(luid, pname, &tgt, NULL, 0);
 | |
|   }
 | |
|  
 | |
|   if (!status) {
 | |
|     printf("%s",getenv("KRB5CCNAME")); /* return via stdout to caller */
 | |
|     DEEDEBUG2("KRB5CCNAME=%s\n",getenv("KRB5CCNAME"));
 | |
|   }
 | |
| 
 | |
|   DEEDEBUG2("Returning status %d\n",status);
 | |
|   return (status);
 | |
| }
 |