示例#1
0
文件: kinit.c 项目: brianmay/heimdal
static void
get_princ(krb5_context context, krb5_principal *principal, const char *name)
{
    krb5_error_code ret;
    krb5_principal tmp;
    int parseflags = 0;
    char *user_realm;

    if (name == NULL) {
	krb5_ccache ccache;

	/* If credential cache provides a client principal, use that. */
	if (krb5_cc_default(context, &ccache) == 0) {
	    ret = krb5_cc_get_principal(context, ccache, principal);
	    krb5_cc_close(context, ccache);
	    if (ret == 0)
		return;
	}
    }

    user_realm = get_user_realm(context);

    if (name) {
	if (canonicalize_flag || enterprise_flag)
	    parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;

	parse_name_realm(context, name, parseflags, user_realm, &tmp);

	if (user_realm && krb5_principal_get_num_comp(context, tmp) > 1) {
	    /* Principal is instance qualified, reparse with default realm. */
	    krb5_free_principal(context, tmp);
	    parse_name_realm(context, name, parseflags, NULL, principal);
	} else {
	    *principal = tmp;
	}
    } else {
	get_default_principal(context, principal);
	if (user_realm)
	    set_princ_realm(context, *principal, user_realm);
    }

    if (user_realm)
	free(user_realm);
}
示例#2
0
/*
 * Log to a cell.  If the cell has already been logged to, return without
 * doing anything.  Otherwise, log to it and mark that it has been logged
 * to.
 */
static int auth_to_cell(krb5_context context, char *user, char *cell, char *realm)
{
    int status = 0;
    char username[BUFSIZ];	/* To hold client username structure */
    afs_int32 viceId;		/* AFS uid of user */

    char name[ANAME_SZ];	/* Name of afs key */
    char primary_instance[INST_SZ];	/* Instance of afs key */
    char secondary_instance[INST_SZ];	/* Backup instance to try */
    int try_secondary = 0;		/* Flag to indicate if we try second */
    char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
    char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
    char local_cell[MAXCELLCHARS+1];
    char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
    static char lastcell[MAXCELLCHARS+1] = { 0 };
    static char confname[512] = { 0 };
    krb5_creds *v5cred = NULL;
    struct ktc_principal aserver;
    struct ktc_principal aclient;
    struct ktc_token atoken, btoken;
    int afssetpag = 0, uid = -1;
    struct passwd *pwd;

    memset(name, 0, sizeof(name));
    memset(primary_instance, 0, sizeof(primary_instance));
    memset(secondary_instance, 0, sizeof(secondary_instance));
    memset(realm_of_user, 0, sizeof(realm_of_user));
    memset(realm_of_cell, 0, sizeof(realm_of_cell));
    syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog starting: user %s uid %d", user, getuid());
    if (confname[0] == '\0') {
        strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
        confname[sizeof(confname) - 2] = '\0';
    }

    /* NULL or empty cell returns information on local cell */
    if ((status = get_cellconfig(cell, &ak_cellconfig,
                                 local_cell, linkedcell))) {
        syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_cellconfig returns %d", status);
        return(status);
    }

    strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
    cell_to_use[MAXCELLCHARS] = 0;

    /*
     * Find out which realm we're supposed to authenticate to.  If one
     * is not included, use the kerberos realm found in the credentials
     * cache.
     */

    if (realm && realm[0]) {
        strcpy(realm_of_cell, realm);
    }
    else {
        char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, FALSE);

        if (!afs_realm) {
            syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
            return AFSCONF_FAILURE;
        }

        strcpy(realm_of_cell, afs_realm);
    }

    /* We use the afs.<cellname> convention here...
     *
     * Doug Engert's original code had principals of the form:
     *
     * "afsx/cell@realm"
     *
     * in the KDC, so the name wouldn't conflict with DFS.  Since we're
     * not using DFS, I changed it just to look for the following
     * principals:
     *
     * afs/<cell>@<realm>
     * afs@<realm>
     *
     * Because people are transitioning from afs@realm to afs/cell,
     * we configure things so that if the first one isn't found, we
     * try the second one.  You can select which one you prefer with
     * a configure option.
     */

    strcpy(name, AFSKEY);

    if (1 || strcasecmp(cell_to_use, realm_of_cell) != 0) {
        strncpy(primary_instance, cell_to_use, sizeof(primary_instance));
        primary_instance[sizeof(primary_instance)-1] = '\0';
        if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
            try_secondary = 1;
            secondary_instance[0] = '\0';
        }
    } else {
        primary_instance[0] = '\0';
        try_secondary = 1;
        strncpy(secondary_instance, cell_to_use,
                sizeof(secondary_instance));
        secondary_instance[sizeof(secondary_instance)-1] = '\0';
    }

    /*
     * Extract the session key from the ticket file and hand-frob an
     * afs style authenticator.
     */

    /*
     * Try to obtain AFS tickets.  Because there are two valid service
     * names, we will try both, but trying the more specific first.
     *
     *	afs/<cell>@<realm> i.e. allow for single name with "."
     * 	afs@<realm>
     */

    status = get_credv5(context, user, name, primary_instance, realm_of_cell,
                        &v5cred);

    if ((status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
            status == KRB5KRB_ERR_GENERIC) && !realm_of_cell[0]) {
        char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, TRUE);

        if (!afs_realm) {
            syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
            return AFSCONF_FAILURE;
        }

        strcpy(realm_of_cell, afs_realm);

        if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
            try_secondary = 1;
            secondary_instance[0] = '\0';
        }

        status = get_credv5(context, user, name, primary_instance,
                            realm_of_cell, &v5cred);
    }
    if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
            status == KRB5KRB_ERR_GENERIC) {
        if (try_secondary)
            status = get_credv5(context, user, name, secondary_instance,
                                realm_of_cell, &v5cred);
    }

    if (status) {
        syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_credv5 returns %d", status);
        return status;
    }

    strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
    strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
    strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);

    /*
     * The default is to use rxkad2b, which means we put in a full
     * V5 ticket.  If the user specifies -524, we talk to the
     * 524 ticket converter.
     */

    {
        char *p;
        int len;

        len = min(get_princ_len(context, v5cred->client, 0),
                  second_comp(context, v5cred->client) ?
                  MAXKTCNAMELEN - 2 : MAXKTCNAMELEN - 1);
        strncpy(username, get_princ_str(context, v5cred->client, 0), len);
        username[len] = '\0';

        if (second_comp(context, v5cred->client)) {
            strcat(username, ".");
            p = username + strlen(username);
            len = min(get_princ_len(context, v5cred->client, 1),
                      MAXKTCNAMELEN - strlen(username) - 1);
            strncpy(p, get_princ_str(context, v5cred->client, 1), len);
            p[len] = '\0';
        }

        memset(&atoken, 0, sizeof(atoken));
        atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
        atoken.startTime = v5cred->times.starttime;;
        atoken.endTime = v5cred->times.endtime;
        memcpy(&atoken.sessionKey, get_cred_keydata(v5cred),
               get_cred_keylen(v5cred));
        atoken.ticketLen = v5cred->ticket.length;
        memcpy(atoken.ticket, v5cred->ticket.data, atoken.ticketLen);
    }

    if ((status = get_user_realm(context, realm_of_user))) {
        syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_user_realm returns %d", status);
        return KRB5_REALM_UNKNOWN;
    }
    if (strcmp(realm_of_user, realm_of_cell)) {
        strcat(username, "@");
        strcat(username, realm_of_user);
    }

    strcpy(lastcell, aserver.cell);

    /*
     * 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 0
    /* This actually crashes long-running daemons */
    if (!pr_Initialize (0, confname, aserver.cell))
        status = pr_SNameToId (username, &viceId);
    if ((status == 0) && (viceId != ANONYMOUSID))
        sprintf (username, "AFS ID %d", (int) viceId);
#else
    /*
     * This actually only works assuming that your uid and pts space match
     * and probably this works only for the local cell anyway.
     */

    if ((uid = getuid()) == 0) {
        if ((pwd = getpwnam(user)) == NULL) {
            syslog(LOG_AUTH|LOG_ERR, "LAM aklog: getpwnam %s failed", user);
            return AUTH_FAILURE;
        }
    }

    /* Don't do first-time registration. Handle only the simple case */
    if ((status == 0) && (viceId != ANONYMOUSID))
        sprintf (username, "AFS ID %d", ((uid==0)?(int)pwd->pw_uid:(int)uid));
#endif

    /* Reset the "aclient" structure before we call ktc_SetToken.
     * This structure was first set by the ktc_GetToken call when
     * we were comparing whether identical tokens already existed.
     */
    strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
    strcpy(aclient.instance, "");
    strncpy(aclient.cell, realm_of_user, MAXKTCREALMLEN - 1);

#ifndef AFS_AIX51_ENV
    /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before
     * this routine, it will not add the token. It is not clear what
     * is going on here! So we will do the following operation.
     * On AIX 5 this kills our parent. So we won't.
     */
    write(2,"",0); /* dummy write */
#endif
    afssetpag = (getpagvalue("afs") > 0) ? 1 : 0;
    if (uid == 0) {
        struct sigaction newAction, origAction;
        pid_t cid, pcid;
        int wstatus;

        sigemptyset(&newAction.sa_mask);
        newAction.sa_handler = SIG_DFL;
        newAction.sa_flags = 0;
        status = sigaction(SIGCHLD, &newAction, &origAction);
        if (status) {
            syslog(LOG_AUTH|LOG_ERR, "LAM aklog: sigaction returned %d", status);
            return AUTH_FAILURE;
        }
        syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: in daemon? forking to set tokens");
        cid = fork();
        if (cid <= 0) {
            syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog child: setting tokens");
            setuid(pwd->pw_uid);
            status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag);
            if (status != 0)
                syslog(LOG_AUTH|LOG_ERR, "LAM aklog child: set tokens, returning %d", status);
            exit((status == 0)?0:255);
        } else {
            do {
                pcid = waitpid(cid, &wstatus, 0);
            } while ((pcid == -1) && (errno == EINTR));
            if ((pcid == cid) && WIFEXITED(wstatus))
                status = WEXITSTATUS(wstatus);
            else
                status = -1;
        }
        syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: collected child status %d", status);
        sigaction(SIGCHLD, &origAction, NULL);
    } else {
        status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag);
    }
    if (status != 0)
        syslog(LOG_AUTH|LOG_ERR, "LAM aklog: set tokens returned %d", status);
    else
        syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: set tokens, pag %d", getpagvalue("afs"));
    return(status);
}