/*
 * Copyright 1994 University of Wisconsin-Madison
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of Wisconsin-Madison not
 * be used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  The University of
 * Wisconsin-Madison makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 *
 * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *           Tim Theisen           Associate Researcher
 * Internet: tim@cs.wisc.edu       Department of Computer Sciences
 *     UUCP: uwvax!tim             University of Wisconsin-Madison
 *    Phone: (608)262-0438         1210 West Dayton Street
 *      FAX: (608)262-9777         Madison, WI   53706-1685
 */

#include <stdio.h>
#include <kerberos/com_err.h>

#include <krb5/krb5.h>
#include <krb5/ext-proto.h>
#include <krb5/los-proto.h>

#include <krb.h>

#include <krb524.h>

#include <afs/param.h>
#include <afs/auth.h>
#include <afs/cellconfig.h>
#include <afs/vice.h>
#include <afs/venus.h>
#include <afs/ptserver.h>

#define AFSKEY "afs"
#define AFSINST ""

/*
 * Stuff kerberos 5 ticket into token.
 * Returns 0 on success, otherwise an error code.
 * Prints to stderr all problems.
 */
int
#ifdef __STDC__
k5token(char *cache_name, int newpag)
#else
k5token(cache_name, newpag)
    char *cache_name;		/* "FILE:/tmp/krb5_pidXXXXX", for example. */
				/* NULL users the default: "/tmp/krb5cc_uid" */
    int newpag;			/* Whether to create a PAG */
#endif
{
    struct afsconf_dir *configdir;
    char local_cell[MAXCELLCHARS+1];
    krb5_error_code code;
    krb5_ccache ccache;
    krb5_creds v5creds;
    CREDENTIALS v4creds;
    struct ktc_principal aserver;
    struct ktc_principal aclient;
    struct ktc_token atoken;
    char username[BUFSIZ];
    int status;
    long viceId;

    if (!(configdir = afsconf_Open(AFSCONF_CLIENTNAME))) {
	fprintf(stderr, "k5token: cannot get afs configuration.\n");
	return 1;
    }
    if (afsconf_GetLocalCell(configdir, local_cell, MAXCELLCHARS)) {
	fprintf(stderr, "k5token: cannot determine local cell.\n");
	return 1;
    }
    (void) afsconf_Close(configdir);
    if (newpag) {
	if (code = setpag()) {
	    fprintf(stderr, "k5token: cannot create new PAG.\n");
	    return code;
	}
    }
    if (cache_name) {
	if (code = krb5_cc_resolve(cache_name, &ccache)) {
	    com_err("k5login", code, "while getting named cache");
	    return code;
	}
    } else {
	if (code = krb5_cc_default(&ccache)) {
	    com_err("k5login", code, "while getting default cache");
	    return code;
	}
    }
    memset((char *)&v5creds, 0, sizeof(v5creds));
    if (code = krb5_sname_to_principal(local_cell,AFSKEY,KRB5_NT_UNKNOWN,
				       &v5creds.server)) {
	com_err ("k5token", code, "error while constructing service name");
	return code;
    }
    if (code = krb5_cc_get_principal(ccache, &v5creds.client)) {
	com_err ("k5token", code, "failure on principal");
	krb5_free_cred_contents(&v5creds);
	return code;
    }
    if (code = krb5_get_credentials(0, ccache, &v5creds)) {
	com_err ("k5token", code, "failure on credentials");
	krb5_free_cred_contents(&v5creds);
	return code;
    }
    if (code = krb524_convert_creds_kdc(&v5creds, &v4creds)) {
	com_err("k5token", code, "converting to V4 credentials");
	return code;
    }
    strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
    strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
    strncpy(aserver.cell, local_cell, MAXKTCREALMLEN - 1);

    strcpy (username, v4creds.pname);
    if (v4creds.pinst[0]) {
	strcat (username, ".");
	strcat (username, v4creds.pinst);
    }

    atoken.kvno = v4creds.kvno;
    atoken.startTime = v5creds.times.starttime;
    atoken.endTime = v5creds.times.endtime;
    memcpy(&atoken.sessionKey, v4creds.session, 8);
    atoken.ticketLen = v4creds.ticket_st.length;
    memcpy(atoken.ticket, v4creds.ticket_st.dat, atoken.ticketLen);

    if (!pr_Initialize (0, AFSCONF_CLIENTNAME, aserver.cell))
	status = pr_SNameToId (username, &viceId);
    
    /*
     * This is a crock, but it is Transarc's crock, so
     * we have to play along in order to get the
     * functionality.  The way the afs id is stored is
     * as a string in the username field of the token.
     * Contrary to what you may think by looking at
     * the code for tokens, this hack (AFS ID %d) will
     * not work if you change %d to something else.
     */
    if ((status == 0) && (viceId != ANONYMOUSID))
	sprintf (aclient.name, "AFS ID %d", viceId);

    strcpy(aclient.instance, "");
    strncpy(aclient.cell, v4creds.realm, MAXKTCREALMLEN - 1);
    if (status = ktc_SetToken(&aserver, &atoken, &aclient)) {
	fprintf(stderr, "k5token: unable to obtain tokens for cell %s.\n");
    }

    return status;
}
