Beispiel #1
0
int
my_init(void)
{
    PyObject *mainmodule;
    FILE *f;

    Py_Initialize ();
//    fprintf(stderr, "trying to load %s\n", SCRIPT_PATH);
    f = fopen(SCRIPT_PATH, "r");
    if (f == NULL) {
        if (sctx)
            krb5_set_error_message(sctx, -1,
                                   "couldn't open Python script %s (%s)",
                                   SCRIPT_PATH, strerror(errno));
        return -1;
    }
    set_cloexec_file(f);
    PyRun_SimpleFile (f, SCRIPT_PATH);
    fclose(f);
    mainmodule = PyModule_GetDict(PyImport_AddModule("__main__"));
    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
    locatefn = PyDict_GetItemString (mainmodule, LOOKUP_FUNC_NAME);
    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
    /* Don't DECREF mainmodule, it's sometimes causing crashes.  */
    if (locatefn == 0)
        return -1;
    if (!PyCallable_Check (locatefn)) {
        Py_DECREF (locatefn);
        locatefn = 0;
        return -1;
    }
    if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; }
    return 0;
}
Beispiel #2
0
krb5_error_code
krb5_ktsrvint_open(krb5_context context, krb5_keytab id)
{
    KTFILEP(id) = fopen(KTFILENAME(id), READ_MODE);
    if (!KTFILEP(id))
	return errno;
    set_cloexec_file(KTFILEP(id));
    return 0;
}
Beispiel #3
0
/* Open and parse the ACL file. */
static krb5_error_code
load_acl_file(krb5_context context, const char *fname, struct acl_state *state)
{
    krb5_error_code ret;
    FILE *fp;
    char *line;
    struct acl_entry **entry_slot;
    int lineno, incr;

    state->list = NULL;

    /* Open the ACL file for reading. */
    fp = fopen(fname, "r");
    if (fp == NULL) {
        krb5_klog_syslog(LOG_ERR, _("%s while opening ACL file %s"),
                         error_message(errno), fname);
        ret = errno;
        k5_setmsg(context, errno, _("Cannot open %s: %s"), fname,
                  error_message(ret));
        return ret;
    }

    set_cloexec_file(fp);
    lineno = 1;
    incr = 0;
    entry_slot = &state->list;

    /* Get a non-comment line. */
    while ((line = get_line(fp, fname, &lineno, &incr)) != NULL) {
        /* Parse it.  Fail out on syntax error. */
        *entry_slot = parse_line(context, line, fname);
        if (*entry_slot == NULL) {
            krb5_klog_syslog(LOG_ERR,
                             _("%s: syntax error at line %d <%.10s...>"),
                             fname, lineno, line);
            k5_setmsg(context, EINVAL,
                      _("%s: syntax error at line %d <%.10s...>"),
                      fname, lineno, line);
            free_acl_entries(state);
            free(line);
            fclose(fp);
            return EINVAL;
        }
        entry_slot = &(*entry_slot)->next;
        free(line);
    }

    fclose(fp);
    return 0;
}
Beispiel #4
0
SETRPCENT_TYPE setrpcent(int f)
{
	register struct rpcdata *d = _rpcdata();

	if (d == 0)
		return;
	if (d->rpcf == NULL) {
		d->rpcf = fopen(RPCDB, "r");
		if (d->rpcf)
		    set_cloexec_file(d->rpcf);
	} else
		rewind(d->rpcf);
	if (d->current)
		free(d->current);
	d->current = NULL;
	d->stayopen |= f;
}
Beispiel #5
0
struct rpcent *
getrpcent(void)
{
	struct rpcent *hp;
	int reason;
	char *key = NULL, *val = NULL;
	int keylen, vallen;
	register struct rpcdata *d = _rpcdata();

	if (d == 0)
		return(NULL);
	if (d->rpcf == NULL) {
	    if ((d->rpcf = fopen(RPCDB, "r")) == NULL)
		return (NULL);
	    set_cloexec_file(d->rpcf);
	}
	if (fgets(d->line, BUFSIZ, d->rpcf) == NULL)
		return (NULL);
	return interpret(d->line, strlen(d->line));
}
Beispiel #6
0
krb5_error_code
osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
                int magic)
{
    osa_adb_db_t db;
    static struct _locklist *locklist = NULL;
    struct _locklist *lockp;
    krb5_error_code code;

    if (dbp == NULL || filename == NULL)
        return EINVAL;

    db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
    if (db == NULL)
        return ENOMEM;

    memset(db, 0, sizeof(*db));
    db->info.hash = NULL;
    db->info.bsize = 256;
    db->info.ffactor = 8;
    db->info.nelem = 25000;
    db->info.lorder = 0;

    db->btinfo.flags = 0;
    db->btinfo.cachesize = 0;
    db->btinfo.psize = 4096;
    db->btinfo.lorder = 0;
    db->btinfo.minkeypage = 0;
    db->btinfo.compare = NULL;
    db->btinfo.prefix = NULL;
    /*
     * A process is allowed to open the same database multiple times
     * and access it via different handles.  If the handles use
     * distinct lockinfo structures, things get confused: lock(A),
     * lock(B), release(B) will result in the kernel unlocking the
     * lock file but handle A will still think the file is locked.
     * Therefore, all handles using the same lock file must share a
     * single lockinfo structure.
     *
     * It is not sufficient to have a single lockinfo structure,
     * however, because a single process may also wish to open
     * multiple different databases simultaneously, with different
     * lock files.  This code used to use a single static lockinfo
     * structure, which means that the second database opened used
     * the first database's lock file.  This was Bad.
     *
     * We now maintain a linked list of lockinfo structures, keyed by
     * lockfilename.  An entry is added when this function is called
     * with a new lockfilename, and all subsequent calls with that
     * lockfilename use the existing entry, updating the refcnt.
     * When the database is closed with fini_db(), the refcnt is
     * decremented, and when it is zero the lockinfo structure is
     * freed and reset.  The entry in the linked list, however, is
     * never removed; it will just be reinitialized the next time
     * init_db is called with the right lockfilename.
     */

    /* find or create the lockinfo structure for lockfilename */
    lockp = locklist;
    while (lockp) {
        if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
            break;
        else
            lockp = lockp->next;
    }
    if (lockp == NULL) {
        /* doesn't exist, create it, add to list */
        lockp = (struct _locklist *) malloc(sizeof(*lockp));
        if (lockp == NULL) {
            free(db);
            return ENOMEM;
        }
        memset(lockp, 0, sizeof(*lockp));
        lockp->lockinfo.filename = strdup(lockfilename);
        if (lockp->lockinfo.filename == NULL) {
            free(lockp);
            free(db);
            return ENOMEM;
        }
        lockp->next = locklist;
        locklist = lockp;
    }

    /* now initialize lockp->lockinfo if necessary */
    if (lockp->lockinfo.lockfile == NULL) {
        if ((code = krb5int_init_context_kdc(&lockp->lockinfo.context))) {
            free(db);
            return((krb5_error_code) code);
        }

        /*
         * needs be open read/write so that write locking can work with
         * POSIX systems
         */
        if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
            /*
             * maybe someone took away write permission so we could only
             * get shared locks?
             */
            if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r"))
                    == NULL) {
                free(db);
                return OSA_ADB_NOLOCKFILE;
            }
        }
        set_cloexec_file(lockp->lockinfo.lockfile);
        lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
    }

    /* lockp is set, lockinfo is initialized, update the reference count */
    db->lock = &lockp->lockinfo;
    db->lock->refcnt++;

    db->opencnt = 0;
    db->filename = strdup(filename);
    db->magic = magic;

    *dbp = db;

    return OSA_ADB_OK;
}
Beispiel #7
0
krb5_error_code
krb5_ldap_readpassword(krb5_context context, krb5_ldap_context *ldap_context,
                       unsigned char **password)
{
    int                         entryfound=0;
    krb5_error_code             st=0;
    char                        line[RECORDLEN]="0", *start=NULL, *file=NULL;
    char                        errbuf[1024];
    FILE                        *fptr=NULL;

    *password = NULL;

    if (ldap_context->service_password_file)
        file = ldap_context->service_password_file;

#ifndef HAVE_STRERROR_R
# undef strerror_r
# define strerror_r(ERRNUM, BUF, SIZE) (strncpy(BUF, strerror(ERRNUM), SIZE), BUF[(SIZE)-1] = 0)
#endif

    /* check whether file exists */
    if (access(file, F_OK) < 0) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }

    /* check read access */
    if (access(file, R_OK) < 0) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }

    if ((fptr=fopen(file, "r")) == NULL) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }
    set_cloexec_file(fptr);

    /* get the record from the file */
    while (fgets(line, RECORDLEN, fptr)!= NULL) {
        char tmp[RECORDLEN];

        tmp[0] = '\0';
        /* Handle leading white-spaces */
        for (start = line; isspace(*start); ++start);

        /* Handle comment lines */
        if (*start == '!' || *start == '#')
            continue;
        sscanf(line, "%*[ \t]%[^#]", tmp);
        if (tmp[0] == '\0')
            sscanf(line, "%[^#]", tmp);
        if (strcasecmp(tmp, ldap_context->bind_dn) == 0) {
            entryfound = 1; /* service_dn record found !!! */
            break;
        }
    }
    fclose (fptr);

    if (entryfound == 0)  {
        st = KRB5_KDB_SERVER_INTERNAL_ERR;
        krb5_set_error_message (context, st, "Bind DN entry missing in stash file");
        goto rp_exit;
    }
    /* replace the \n with \0 */
    start = strchr(line, '\n');
    if (start)
        *start = '\0';

    start = strchr(line, '#');
    if (start == NULL) {
        /* password field missing */
        st = KRB5_KDB_SERVER_INTERNAL_ERR;
        krb5_set_error_message (context, st, "Stash file entry corrupt");
        goto rp_exit;
    }
    ++ start;
    /* Extract the plain password / certificate file information */
    {
        struct data PT, CT;

        /* Check if the entry has the path of a certificate */
        if (!strncmp(start, "{FILE}", strlen("{FILE}"))) {
            /* Set *password = {FILE}<path to cert>\0<cert password> */
            size_t len = strlen(start);

            *password = (unsigned char *)malloc(len + 2);
            if (*password == NULL) {
                st = ENOMEM;
                goto rp_exit;
            }
            memcpy(*password, start, len);
            (*password)[len] = '\0';
            (*password)[len + 1] = '\0';
            goto got_password;
        } else {
            CT.value = (unsigned char *)start;
            CT.len = strlen((char *)CT.value);
            st = dec_password(CT, &PT);
            if (st != 0) {
                switch (st) {
                case ERR_NO_MEM:
                    st = ENOMEM;
                    break;
                case ERR_PWD_ZERO:
                    st = EINVAL;
                    krb5_set_error_message(context, st, "Password has zero length");
                    break;
                case ERR_PWD_BAD:
                    st = EINVAL;
                    krb5_set_error_message(context, st, "Password corrupted");
                    break;
                case ERR_PWD_NOT_HEX:
                    st = EINVAL;
                    krb5_set_error_message(context, st, "Not a hexadecimal password");
                    break;
                default:
                    st = KRB5_KDB_SERVER_INTERNAL_ERR;
                    break;
                }
                goto rp_exit;
            }
            *password = PT.value;
        }
    }
got_password:

rp_exit:
    if (st) {
        if (*password)
            free (*password);
        *password = NULL;
    }
    return st;
}
Beispiel #8
0
static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
				    int can_create)
{
	FILE		*f;
	profile_filespec_t new_file;
	profile_filespec_t old_file;
	errcode_t	retval = 0;

	retval = ENOMEM;
	
	new_file = old_file = 0;
	if (asprintf(&new_file, "%s.$$$", outfile) < 0) {
	    new_file = NULL;
	    goto errout;
	}
	if (asprintf(&old_file, "%s.bak", outfile) < 0) {
	    old_file = NULL;
	    goto errout;
	}

	errno = 0;

	f = fopen(new_file, "w");
	if (!f) {
		retval = errno;
		if (retval == 0)
			retval = PROF_FAIL_OPEN;
		goto errout;
	}

	set_cloexec_file(f);
	profile_write_tree_file(data->root, f);
	if (fclose(f) != 0) {
		retval = errno;
		goto errout;
	}

	unlink(old_file);
	if (make_hard_link(outfile, old_file) == 0) {
	    /* Okay, got the hard link.  Yay.  Now we've got our
	       backup version, so just put the new version in
	       place.  */
	    if (rename(new_file, outfile)) {
		/* Weird, the rename didn't work.  But the old version
		   should still be in place, so no special cleanup is
		   needed.  */
		retval = errno;
		goto errout;
	    }
	} else if (errno == ENOENT && can_create) {
	    if (rename(new_file, outfile)) {
		retval = errno;
		goto errout;
	    }
	} else {
	    /* Couldn't make the hard link, so there's going to be a
	       small window where data->filespec does not refer to
	       either version.  */
#ifndef _WIN32
	    sync();
#endif
	    if (rename(outfile, old_file)) {
		retval = errno;
		goto errout;
	    }
	    if (rename(new_file, outfile)) {
		retval = errno;
		rename(old_file, outfile); /* back out... */
		goto errout;
	    }
	}

	data->flags = 0;
	retval = 0;

errout:
	if (new_file)
		free(new_file);
	if (old_file)
		free(old_file);
	return retval;
}
Beispiel #9
0
errcode_t profile_update_file_data(prf_data_t data)
{
	errcode_t retval;
#ifdef HAVE_STAT
	struct stat st;
	unsigned long frac;
	time_t now;
#endif
	FILE *f;

	retval = k5_mutex_lock(&data->lock);
	if (retval)
	    return retval;

#ifdef HAVE_STAT
	now = time(0);
	if (now == data->last_stat && data->root != NULL) {
	    k5_mutex_unlock(&data->lock);
	    return 0;
	}
	if (stat(data->filespec, &st)) {
	    retval = errno;
	    k5_mutex_unlock(&data->lock);
	    return retval;
	}
	data->last_stat = now;
#if defined HAVE_STRUCT_STAT_ST_MTIMENSEC
	frac = st.st_mtimensec;
#elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
	frac = st.st_mtimespec.tv_nsec;
#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
	frac = st.st_mtim.tv_nsec;
#else
	frac = 0;
#endif
	if (st.st_mtime == data->timestamp
	    && frac == data->frac_ts
	    && data->root != NULL) {
	    k5_mutex_unlock(&data->lock);
	    return 0;
	}
	if (data->root) {
		profile_free_node(data->root);
		data->root = 0;
	}
	if (data->comment) {
		free(data->comment);
		data->comment = 0;
	}
#else
	/*
	 * If we don't have the stat() call, assume that our in-core
	 * memory image is correct.  That is, we won't reread the
	 * profile file if it changes.
	 */
	if (data->root) {
	    k5_mutex_unlock(&data->lock);
	    return 0;
	}
#endif
	errno = 0;
	f = fopen(data->filespec, "r");
	if (f == NULL) {
		retval = errno;
		k5_mutex_unlock(&data->lock);
		if (retval == 0)
			retval = ENOENT;
		return retval;
	}
	set_cloexec_file(f);
	data->upd_serial++;
	data->flags &= PROFILE_FILE_SHARED;  /* FIXME same as '=' operator */
	retval = profile_parse_file(f, &data->root);
	fclose(f);
	if (retval) {
	    k5_mutex_unlock(&data->lock);
	    return retval;
	}
	assert(data->root != NULL);
#ifdef HAVE_STAT
	data->timestamp = st.st_mtime;
	data->frac_ts = frac;
#endif
	k5_mutex_unlock(&data->lock);
	return 0;
}
Beispiel #10
0
krb5_boolean KRB5_CALLCONV
krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser)
{
    struct stat sbuf;
    struct passwd *pwd;
    char pbuf[MAXPATHLEN];
    krb5_boolean isok = FALSE;
    FILE *fp;
    char kuser[MAX_USERNAME];
    char *princname;
    char linebuf[BUFSIZ];
    char *newline;
    int gobble;

    /* no account => no access */
    char pwbuf[BUFSIZ];
    struct passwd pwx;
    if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0)
	return(FALSE);
    (void) strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1);
    pbuf[sizeof(pbuf) - 1] = '\0';
    (void) strncat(pbuf, "/.k5login", sizeof(pbuf) - 1 - strlen(pbuf));

    if (access(pbuf, F_OK)) {	 /* not accessible */
	/*
	 * if he's trying to log in as himself, and there is no .k5login file,
	 * let him.  To find out, call
	 * krb5_aname_to_localname to convert the principal to a name
	 * which we can string compare. 
	 */
	if (!(krb5_aname_to_localname(context, principal,
				      sizeof(kuser), kuser))
	    && (strcmp(kuser, luser) == 0)) {
	    return(TRUE);
	}
    }
    if (krb5_unparse_name(context, principal, &princname))
	return(FALSE);			/* no hope of matching */

    /* open ~/.k5login */
    if ((fp = fopen(pbuf, "r")) == NULL) {
	free(princname);
	return(FALSE);
    }
    set_cloexec_file(fp);
    /*
     * For security reasons, the .k5login file must be owned either by
     * the user himself, or by root.  Otherwise, don't grant access.
     */
    if (fstat(fileno(fp), &sbuf)) {
	fclose(fp);
	free(princname);
	return(FALSE);
    }
    if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) {
	fclose(fp);
	free(princname);
	return(FALSE);
    }

    /* check each line */
    while (!isok && (fgets(linebuf, BUFSIZ, fp) != NULL)) {
	/* null-terminate the input string */
	linebuf[BUFSIZ-1] = '\0';
	newline = NULL;
	/* nuke the newline if it exists */
	if ((newline = strchr(linebuf, '\n')))
	    *newline = '\0';
	if (!strcmp(linebuf, princname)) {
	    isok = TRUE;
	    continue;
	}
	/* clean up the rest of the line if necessary */
	if (!newline)
	    while (((gobble = getc(fp)) != EOF) && gobble != '\n');
    }
    free(princname);
    fclose(fp);
    return(isok);
}
Beispiel #11
0
/*
 * Determine whether principal is authorized to log in as luser according to
 * the user's k5login file.  Return ACCEPT if the k5login file authorizes the
 * principal, PASS if the k5login file does not exist, or REJECT if the k5login
 * file exists but does not authorize the principal.  If k5login files are
 * configured to be non-authoritative, pass instead of rejecting.
 */
static enum result
k5login_ok(krb5_context context, krb5_principal principal, const char *luser)
{
    int authoritative = TRUE, gobble;
    enum result result = REJECT;
    char *filename = NULL, *princname = NULL;
    char *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ];
    struct stat sbuf;
    struct passwd pwx, *pwd;
    FILE *fp = NULL;

    if (profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
                            KRB5_CONF_K5LOGIN_AUTHORITATIVE, NULL, TRUE,
                            &authoritative) != 0)
        goto cleanup;

    /* Get the local user's homedir and uid. */
    if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0)
        goto cleanup;

    if (get_k5login_filename(context, luser, pwd->pw_dir, &filename) != 0)
        goto cleanup;

    if (access(filename, F_OK) != 0) {
        result = PASS;
        goto cleanup;
    }

    if (krb5_unparse_name(context, principal, &princname) != 0)
        goto cleanup;

    fp = fopen(filename, "r");
    if (fp == NULL)
        goto cleanup;
    set_cloexec_file(fp);

    /* For security reasons, the .k5login file must be owned either by
     * the user or by root. */
    if (fstat(fileno(fp), &sbuf))
        goto cleanup;
    if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid))
        goto cleanup;

    /* Check each line. */
    while (result != ACCEPT && (fgets(linebuf, sizeof(linebuf), fp) != NULL)) {
        newline = strrchr(linebuf, '\n');
        if (newline != NULL)
            *newline = '\0';
        if (strcmp(linebuf, princname) == 0)
            result = ACCEPT;
        /* Clean up the rest of the line if necessary. */
        if (newline == NULL)
            while (((gobble = getc(fp)) != EOF) && gobble != '\n');
    }

cleanup:
    free(princname);
    free(filename);
    if (fp != NULL)
        fclose(fp);
    /* If k5login files are non-authoritative, never reject. */
    return (!authoritative && result == REJECT) ? PASS : result;
}
Beispiel #12
0
krb5_error_code
krb5_ldap_readpassword(krb5_context context, krb5_ldap_context *ldap_context,
                       unsigned char **password)
{
    int                         entryfound=0;
    krb5_error_code             st=0;
    char                        line[RECORDLEN]="0", *start=NULL, *file=NULL;
    char                        errbuf[1024];
    FILE                        *fptr=NULL;

    *password = NULL;

    if (ldap_context->service_password_file)
        file = ldap_context->service_password_file;

#ifndef HAVE_STRERROR_R
# undef strerror_r
# define strerror_r(ERRNUM, BUF, SIZE) (strncpy(BUF, strerror(ERRNUM), SIZE), BUF[(SIZE)-1] = 0)
#endif

    /* check whether file exists */
    if (access(file, F_OK) < 0) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }

    /* check read access */
    if (access(file, R_OK) < 0) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }

    if ((fptr=fopen(file, "r")) == NULL) {
        st = errno;
        strerror_r(errno, errbuf, sizeof(errbuf));
        krb5_set_error_message (context, st, "%s", errbuf);
        goto rp_exit;
    }
    set_cloexec_file(fptr);

    /* get the record from the file */
    while (fgets(line, RECORDLEN, fptr)!= NULL) {
        char tmp[RECORDLEN];

        tmp[0] = '\0';
        /* Handle leading white-spaces */
        for (start = line; isspace(*start); ++start);

        /* Handle comment lines */
        if (*start == '!' || *start == '#')
            continue;
        sscanf(line, "%*[ \t]%[^#]", tmp);
        if (tmp[0] == '\0')
            sscanf(line, "%[^#]", tmp);
        if (strcasecmp(tmp, ldap_context->bind_dn) == 0) {
            entryfound = 1; /* service_dn record found !!! */
            break;
        }
    }
    fclose (fptr);

    if (entryfound == 0)  {
        st = KRB5_KDB_SERVER_INTERNAL_ERR;
        krb5_set_error_message(context, st,
                               _("Bind DN entry missing in stash file"));
        goto rp_exit;
    }
    /* replace the \n with \0 */
    start = strchr(line, '\n');
    if (start)
        *start = '\0';

    start = strchr(line, '#');
    if (start == NULL) {
        /* password field missing */
        st = KRB5_KDB_SERVER_INTERNAL_ERR;
        krb5_set_error_message(context, st, _("Stash file entry corrupt"));
        goto rp_exit;
    }
    ++ start;

    /* Extract the plain password information. */
    st = dec_password(context, start, password);

rp_exit:
    if (st) {
        if (*password)
            free (*password);
        *password = NULL;
    }
    return st;
}