예제 #1
0
krb5_error_code
osa_adb_release_lock(osa_adb_db_t db)
{
    int ret, fd;

    if (!db->lock->lockcnt)            /* lock already unlocked */
        return OSA_ADB_NOTLOCKED;

    if (--db->lock->lockcnt == 0) {
        if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
            /* now we need to create the file since it does not exist */
            fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
                                0600);
            if (fd < 0)
                return OSA_ADB_NOLOCKFILE;
            set_cloexec_fd(fd);
            if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL)
                return OSA_ADB_NOLOCKFILE;
        } else if ((ret = krb5_lock_file(db->lock->context,
                                         fileno(db->lock->lockfile),
                                         KRB5_LOCKMODE_UNLOCK)))
            return ret;

        db->lock->lockmode = 0;
    }
    return OSA_ADB_OK;
}
예제 #2
0
파일: pager.c 프로젝트: PADL/krb5
int ss_pager_create()
{
    int filedes[2];

    if (pipe(filedes) != 0)
        return(-1);

    switch((int) fork()) {
    case -1:
        return(-1);
    case 0:
        /*
         * Child; dup read half to 0, close all but 0, 1, and 2
         */
        if (dup2(filedes[0], 0) == -1)
            exit(1);
        ss_page_stdin();
    default:
        /*
         * Parent:  close "read" side of pipe, return
         * "write" side.
         */
        (void) close(filedes[0]);
        set_cloexec_fd(filedes[1]);
        return(filedes[1]);
    }
}
예제 #3
0
파일: rc_io.c 프로젝트: Akasurde/krb5
krb5_error_code
krb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn)
{
    krb5_int16 rc_vno = htons(KRB5_RC_VNO);
    krb5_error_code retval = 0;
    int flags, do_not_unlink = 0;
    char *dir;
    size_t dirlen;

    GETDIR;
    if (fn && *fn) {
        if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, *fn) < 0)
            return KRB5_RC_IO_MALLOC;
        d->fd = -1;
        do {
            if (unlink(d->fn) == -1 && errno != ENOENT)
                break;
            flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY;
            d->fd = THREEPARAMOPEN(d->fn, flags, 0600);
        } while (d->fd == -1 && errno == EEXIST);
    } else {
        retval = krb5_rc_io_mkstemp(context, d, dir);
        if (retval)
            goto cleanup;
        if (d->fd != -1 && fn) {
            *fn = strdup(d->fn + dirlen);
            if (*fn == NULL) {
                free(d->fn);
                return KRB5_RC_IO_MALLOC;
            }
        }
    }
    if (d->fd == -1) {
        retval = rc_map_errno(context, errno, d->fn, "create");
        if (retval == KRB5_RC_IO_PERM)
            do_not_unlink = 1;
        goto cleanup;
    }
    set_cloexec_fd(d->fd);
    retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno,
                              sizeof(rc_vno));
    if (retval)
        goto cleanup;

    retval = krb5_rc_io_sync(context, d);

cleanup:
    if (retval) {
        if (d->fn) {
            if (!do_not_unlink)
                (void) unlink(d->fn);
            free(d->fn);
            d->fn = NULL;
        }
        if (d->fd != -1) {
            (void) close(d->fd);
        }
    }
    return retval;
}
예제 #4
0
파일: pager.c 프로젝트: PADL/krb5
        /*
         * Parent:  close "read" side of pipe, return
         * "write" side.
         */
        (void) close(filedes[0]);
        set_cloexec_fd(filedes[1]);
        return(filedes[1]);
    }
}
#else /* don't fork */
int ss_pager_create()
{
    int fd;
    fd = open("/dev/tty", O_WRONLY, 0);
    if (fd >= 0)
        set_cloexec_fd(fd);
    return fd;
}
예제 #5
0
파일: kdb_db2.c 프로젝트: Brainiarc7/pbis
krb5_error_code
krb5_db2_init(krb5_context context)
{
    char   *filename = NULL;
    krb5_db2_context *db_ctx;
    krb5_error_code retval;
    char    policy_db_name[1024], policy_lock_name[1024];

    if (k5db2_inited(context))
        return 0;

    /* Check for presence of our context, if not present, allocate one. */
    if ((retval = k5db2_init_context(context)))
        return (retval);

    db_ctx = context->dal_handle->db_context;
    db_ctx->db = NULL;

    if (!(filename = gen_dbsuffix(db_ctx->db_name, db_ctx->tempdb
                                  ?KDB2_TEMP_LOCK_EXT:KDB2_LOCK_EXT)))
        return ENOMEM;
    db_ctx->db_lf_name = filename;      /* so it gets freed by clear_context */

    /*
     * should be opened read/write so that write locking can work with
     * POSIX systems
     */
    if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
        if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
            retval = errno;
            goto err_out;
        }
    }
    set_cloexec_fd(db_ctx->db_lf_file);
    db_ctx->db_inited++;

    if ((retval = krb5_db2_get_age(context, NULL, &db_ctx->db_lf_time)))
        goto err_out;

    snprintf(policy_db_name, sizeof(policy_db_name), "%s%s.kadm5",
             db_ctx->db_name, db_ctx->tempdb ? "~" : "");
    snprintf(policy_lock_name, sizeof(policy_lock_name),
             "%s.lock", policy_db_name);

    if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
                                  policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
    {
        goto err_out;
    }
    return 0;

err_out:
    db_ctx->db = NULL;
    k5db2_clear_context(db_ctx);
    return (retval);
}
int init_dict(kadm5_config_params *params)
{
    int             fd,
        len,
        i;
    char            *p,
        *t;
    struct  stat    sb;

    if(word_list != NULL && word_block != NULL)
        return KADM5_OK;
    if (! (params->mask & KADM5_CONFIG_DICT_FILE)) {
        krb5_klog_syslog(LOG_INFO, "No dictionary file specified, continuing "
                         "without one.");
        return KADM5_OK;
    }
    if ((fd = open(params->dict_file, O_RDONLY)) == -1) {
        if (errno == ENOENT) {
            krb5_klog_syslog(LOG_ERR,
                             "WARNING!  Cannot find dictionary file %s, "
                             "continuing without one.", params->dict_file);
            return KADM5_OK;
        } else
            return errno;
    }
    set_cloexec_fd(fd);
    if (fstat(fd, &sb) == -1) {
        close(fd);
        return errno;
    }
    if ((word_block = (char *) malloc(sb.st_size + 1)) == NULL)
        return ENOMEM;
    if (read(fd, word_block, sb.st_size) != sb.st_size)
        return errno;
    (void) close(fd);
    word_block[sb.st_size] = '\0';

    p = word_block;
    len = sb.st_size;
    while(len > 0 && (t = memchr(p, '\n', len)) != NULL) {
        *t = '\0';
        len -= t - p + 1;
        p = t + 1;
        word_count++;
    }
    if ((word_list = (char **) malloc(word_count * sizeof(char *))) == NULL)
        return ENOMEM;
    p = word_block;
    for (i = 0; i < word_count; i++) {
        word_list[i] = p;
        p += strlen(p) + 1;
    }
    qsort(word_list, word_count, sizeof(char *), word_compare);
    return KADM5_OK;
}
예제 #7
0
파일: kdb_db2.c 프로젝트: DirectXMan12/krb5
/* Initialize the lock file and policy database fields of dbc.  The db_name and
 * tempdb fields must already be set. */
static krb5_error_code
ctx_init(krb5_db2_context *dbc)
{
    krb5_error_code retval;
    char *polname = NULL, *plockname = NULL;

    retval = ctx_dbsuffix(dbc, SUFFIX_LOCK, &dbc->db_lf_name);
    if (retval)
        return retval;

    /*
     * should be opened read/write so that write locking can work with
     * POSIX systems
     */
    if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDWR, 0666)) < 0) {
        if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDONLY, 0666)) < 0) {
            retval = errno;
            goto cleanup;
        }
    }
    set_cloexec_fd(dbc->db_lf_file);
    dbc->db_inited++;

    retval = ctx_dbsuffix(dbc, SUFFIX_POLICY, &polname);
    if (retval)
        goto cleanup;
    retval = ctx_dbsuffix(dbc, SUFFIX_POLICY_LOCK, &plockname);
    if (retval)
        goto cleanup;
    retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
                             OSA_ADB_POLICY_DB_MAGIC);

cleanup:
    free(polname);
    free(plockname);
    if (retval)
        ctx_clear(dbc);
    return retval;
}
예제 #8
0
/*
 * don't use gethostbyname, which would invoke yellow pages
 */
get_myaddress(struct sockaddr_in *addr)
{
	int s;
	char buf[256 * sizeof (struct ifreq)];
	struct ifconf ifc;
	struct ifreq ifreq, *ifr;
	int len;

	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	    perror("get_myaddress: socket");
	    exit(1);
	}
	set_cloexec_fd(s);
	ifc.ifc_len = sizeof (buf);
	ifc.ifc_buf = buf;
	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
		perror("get_myaddress: ioctl (get interface configuration)");
		exit(1);
	}
	ifr = ifc.ifc_req;
	for (len = ifc.ifc_len; len; len -= sizeof ifreq) {
		ifreq = *ifr;
		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
			perror("get_myaddress: ioctl");
			exit(1);
		}
		if ((ifreq.ifr_flags & IFF_UP) &&
		    ifr->ifr_addr.sa_family == AF_INET) {
			*addr = *((struct sockaddr_in *)&ifr->ifr_addr);
			addr->sin_port = htons(PMAPPORT);
			break;
		}
		ifr++;
	}
	(void) close(s);
}
예제 #9
0
파일: rc_io.c 프로젝트: arkadiyg/krb5
krb5_error_code
krb5_rc_io_move(krb5_context context, krb5_rc_iostuff *new1,
                krb5_rc_iostuff *old)
{
#if defined(_WIN32) || defined(__CYGWIN__)
    char *new_fn = NULL;
    char *old_fn = NULL;
    off_t offset = 0;
    krb5_error_code retval = 0;
    /*
     * Initial work around provided by Tom Sanfilippo to work around
     * poor Windows emulation of POSIX functions.  Rename and dup has
     * different semantics!
     *
     * Additional fixes and explanation provided by [email protected]:
     *
     * First, we save the offset of "old".  Then, we close and remove
     * the "new" file so we can do the rename.  We also close "old" to
     * make sure the rename succeeds (though that might not be
     * necessary on some systems).
     *
     * Next, we do the rename.  If all goes well, we seek the "new"
     * file to the position "old" was at.
     *
     * --- WARNING!!! ---
     *
     * Since "old" is now gone, we mourn its disappearance, but we
     * cannot emulate that Unix behavior...  THIS BEHAVIOR IS
     * DIFFERENT FROM UNIX.  However, it is ok because this function
     * gets called such that "old" gets closed right afterwards.
     */
    offset = lseek(old->fd, 0, SEEK_CUR);

    new_fn = new1->fn;
    new1->fn = NULL;
    close(new1->fd);
    new1->fd = -1;

    unlink(new_fn);

    old_fn = old->fn;
    old->fn = NULL;
    close(old->fd);
    old->fd = -1;

    if (rename(old_fn, new_fn) == -1) { /* MUST be atomic! */
        retval = KRB5_RC_IO_UNKNOWN;
        goto cleanup;
    }

    retval = krb5_rc_io_open_internal(context, new1, 0, new_fn);
    if (retval)
        goto cleanup;

    if (lseek(new1->fd, offset, SEEK_SET) == -1) {
        retval = KRB5_RC_IO_UNKNOWN;
        goto cleanup;
    }

cleanup:
    free(new_fn);
    free(old_fn);
    return retval;
#else
    char *fn = NULL;
    if (rename(old->fn, new1->fn) == -1) /* MUST be atomic! */
        return KRB5_RC_IO_UNKNOWN;
    fn = new1->fn;
    new1->fn = NULL;            /* avoid clobbering */
    (void) krb5_rc_io_close(context, new1);
    new1->fn = fn;
    new1->fd = dup(old->fd);
    set_cloexec_fd(new1->fd);
    return 0;
#endif
}
예제 #10
0
파일: rc_io.c 프로젝트: arkadiyg/krb5
static krb5_error_code
krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
                         char* full_pathname)
{
    krb5_int16 rc_vno;
    krb5_error_code retval = 0;
    int do_not_unlink = 1;
#ifndef NO_USERID
    struct stat sb1, sb2;
#endif
    char *dir;

    dir = getdir();
    if (full_pathname) {
        if (!(d->fn = strdup(full_pathname)))
            return KRB5_RC_IO_MALLOC;
    } else {
        if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, fn) < 0)
            return KRB5_RC_IO_MALLOC;
    }

#ifdef NO_USERID
    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
    if (d->fd == -1) {
        retval = rc_map_errno(context, errno, d->fn, "open");
        goto cleanup;
    }
#else
    d->fd = -1;
    retval = lstat(d->fn, &sb1);
    if (retval != 0) {
        retval = rc_map_errno(context, errno, d->fn, "lstat");
        goto cleanup;
    }
    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
    if (d->fd < 0) {
        retval = rc_map_errno(context, errno, d->fn, "open");
        goto cleanup;
    }
    retval = fstat(d->fd, &sb2);
    if (retval < 0) {
        retval = rc_map_errno(context, errno, d->fn, "fstat");
        goto cleanup;
    }
    /* check if someone was playing with symlinks */
    if ((sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino)
        || (sb1.st_mode & S_IFMT) != S_IFREG)
    {
        retval = KRB5_RC_IO_PERM;
        k5_setmsg(context, retval, "rcache not a file %s", d->fn);
        goto cleanup;
    }
    /* check that non other can read/write/execute the file */
    if (sb1.st_mode & 077) {
        k5_setmsg(context, retval,
                  _("Insecure file mode for replay cache file %s"), d->fn);
        return KRB5_RC_IO_UNKNOWN;
    }
    /* owned by me */
    if (sb1.st_uid != geteuid()) {
        retval = KRB5_RC_IO_PERM;
        k5_setmsg(context, retval, _("rcache not owned by %d"),
                  (int)geteuid());
        goto cleanup;
    }
#endif
    set_cloexec_fd(d->fd);

    do_not_unlink = 0;
    retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno,
                             sizeof(rc_vno));
    if (retval)
        goto cleanup;

    if (ntohs(rc_vno) != KRB5_RC_VNO)
        retval = KRB5_RCACHE_BADVNO;

cleanup:
    if (retval) {
        if (!do_not_unlink)
            (void) unlink(d->fn);
        free(d->fn);
        d->fn = NULL;
        if (d->fd >= 0)
            (void) close(d->fd);
    }
    return retval;
}
예제 #11
0
파일: cc_file.c 프로젝트: arkadiyg/krb5
/* Open and lock the cache file.  If mode is FCC_OPEN_AND_ERASE, initialize it
 * with a header.  Call with the mutex locked. */
static krb5_error_code
open_cache_file(krb5_context context, krb5_ccache id, int mode)
{
    krb5_os_context os_ctx = &context->os_context;
    krb5_error_code ret;
    fcc_data *data = id->data;
    char fcc_fvno[2];
    uint16_t fcc_flen, fcc_tag, fcc_taglen;
    uint32_t time_offset, usec_offset;
    int f, open_flag, lock_flag, cnt;
    char buf[1024];

    k5_cc_mutex_assert_locked(context, &data->lock);
    invalidate_cache(data);

    if (data->fd != NO_FILE) {
        /* Don't know what state it's in; shut down and start anew. */
        (void)krb5_unlock_file(context, data->fd);
        (void)close(data->fd);
        data->fd = NO_FILE;
    }

    switch (mode) {
    case FCC_OPEN_AND_ERASE:
        unlink(data->filename);
        open_flag = O_CREAT | O_EXCL | O_TRUNC | O_RDWR;
        break;
    case FCC_OPEN_RDWR:
        open_flag = O_RDWR;
        break;
    case FCC_OPEN_RDONLY:
    default:
        open_flag = O_RDONLY;
        break;
    }

    f = THREEPARAMOPEN(data->filename, open_flag | O_BINARY, 0600);
    if (f == NO_FILE) {
        if (errno == ENOENT) {
            ret = KRB5_FCC_NOFILE;
            k5_setmsg(context, ret, _("Credentials cache file '%s' not found"),
                      data->filename);
            return ret;
        } else {
            return interpret_errno(context, errno);
        }
    }
    set_cloexec_fd(f);

    data->mode = mode;

    if (data->mode == FCC_OPEN_RDONLY)
        lock_flag = KRB5_LOCKMODE_SHARED;
    else
        lock_flag = KRB5_LOCKMODE_EXCLUSIVE;
    ret = krb5_lock_file(context, f, lock_flag);
    if (ret) {
        (void)close(f);
        return ret;
    }

    if (mode == FCC_OPEN_AND_ERASE) {
        /* write the version number */
        store_16_be(context->fcc_default_format, fcc_fvno);
        data->version = context->fcc_default_format;
        cnt = write(f, fcc_fvno, 2);
        if (cnt != 2) {
            ret = (cnt == -1) ? interpret_errno(context, errno) : KRB5_CC_IO;
            goto done;
        }
        data->fd = f;

        if (data->version == FVNO_4) {
            /* V4 of the credentials cache format allows for header tags */
            fcc_flen = 0;

            if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)
                fcc_flen += 2 + 2 + 4 + 4;

            /* Write header length. */
            ret = store16(context, id, fcc_flen);
            if (ret)
                goto done;

            if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
                /* Write time offset tag. */
                fcc_tag = FCC_TAG_DELTATIME;
                fcc_taglen = 2 * 4;

                ret = store16(context, id, fcc_tag);
                if (ret)
                    goto done;
                ret = store16(context, id, fcc_taglen);
                if (ret)
                    goto done;
                ret = store32(context, id, os_ctx->time_offset);
                if (ret)
                    goto done;
                ret = store32(context, id, os_ctx->usec_offset);
                if (ret)
                    goto done;
            }
        }
        invalidate_cache(data);
        goto done;
    }

    /* Verify a valid version number is there. */
    invalidate_cache(data);
    if (read(f, fcc_fvno, 2) != 2) {
        ret = KRB5_CC_FORMAT;
        goto done;
    }
    data->version = load_16_be(fcc_fvno);
    if (data->version != FVNO_4 && data->version != FVNO_3 &&
        data->version != FVNO_2 && data->version != FVNO_1) {
        ret = KRB5_CCACHE_BADVNO;
        goto done;
    }

    data->fd = f;

    if (data->version == FVNO_4) {
        if (read16(context, id, &fcc_flen) || fcc_flen > sizeof(buf)) {
            ret = KRB5_CC_FORMAT;
            goto done;
        }

        while (fcc_flen) {
            if (fcc_flen < 2 * 2 || read16(context, id, &fcc_tag) ||
                read16(context, id, &fcc_taglen) ||
                fcc_taglen > fcc_flen - 2 * 2) {
                ret = KRB5_CC_FORMAT;
                goto done;
            }

            switch (fcc_tag) {
            case FCC_TAG_DELTATIME:
                if (fcc_taglen != 2 * 4) {
                    ret = KRB5_CC_FORMAT;
                    goto done;
                }
                if (!(context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) ||
                    (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) {
                    if (read_bytes(context, id, buf, fcc_taglen)) {
                        ret = KRB5_CC_FORMAT;
                        goto done;
                    }
                    break;
                }
                if (read32(context, id, NULL, &time_offset) ||
                    read32(context, id, NULL, &usec_offset)) {
                    ret = KRB5_CC_FORMAT;
                    goto done;
                }
                os_ctx->time_offset = time_offset;
                os_ctx->usec_offset = usec_offset;
                os_ctx->os_flags =
                    ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
                     KRB5_OS_TOFFSET_VALID);
                break;
            default:
                if (fcc_taglen && read_bytes(context, id, buf, fcc_taglen)) {
                    ret = KRB5_CC_FORMAT;
                    goto done;
                }
                break;
            }
            fcc_flen -= (2 * 2 + fcc_taglen);
        }
    }

done:
    if (ret) {
        data->fd = -1;
        (void)krb5_unlock_file(context, f);
        (void)close(f);
    }
    return ret;
}
예제 #12
0
파일: kdb_db2.c 프로젝트: Brainiarc7/pbis
/*
 * Destroy the database.  Zero's out all of the files, just to be sure.
 */
static krb5_error_code
destroy_file_suffix(char *dbname, char *suffix)
{
    char   *filename;
    struct stat statb;
    int     nb, fd;
    int     j;
    off_t   pos;
    char    buf[BUFSIZ];
    char    zbuf[BUFSIZ];
    int     dowrite;

    filename = gen_dbsuffix(dbname, suffix);
    if (filename == 0)
        return ENOMEM;
    if ((fd = open(filename, O_RDWR, 0)) < 0) {
        free(filename);
        return errno;
    }
    set_cloexec_fd(fd);
    /* fstat() will probably not fail unless using a remote filesystem
     * (which is inappropriate for the kerberos database) so this check
     * is mostly paranoia.  */
    if (fstat(fd, &statb) == -1) {
        int     retval = errno;
        free(filename);
        return retval;
    }
    /*
     * Stroll through the file, reading in BUFSIZ chunks.  If everything
     * is zero, then we're done for that block, otherwise, zero the block.
     * We would like to just blast through everything, but some DB
     * implementations make holey files and writing data to the holes
     * causes actual blocks to be allocated which is no good, since
     * we're just about to unlink it anyways.
     */
    memset(zbuf, 0, BUFSIZ);
    pos = 0;
    while (pos < statb.st_size) {
        dowrite = 0;
        nb = read(fd, buf, BUFSIZ);
        if (nb < 0) {
            int     retval = errno;
            free(filename);
            return retval;
        }
        for (j = 0; j < nb; j++) {
            if (buf[j] != '\0') {
                dowrite = 1;
                break;
            }
        }
        /* For signedness */
        j = nb;
        if (dowrite) {
            lseek(fd, pos, SEEK_SET);
            nb = write(fd, zbuf, j);
            if (nb < 0) {
                int     retval = errno;
                free(filename);
                return retval;
            }
        }
        pos += nb;
    }
    /* ??? Is fsync really needed?  I don't know of any non-networked
     * filesystem which will discard queued writes to disk if a file
     * is deleted after it is closed.  --jfc */
#ifndef NOFSYNC
    fsync(fd);
#endif
    close(fd);

    if (unlink(filename)) {
        free(filename);
        return (errno);
    }
    free(filename);
    return (0);
}
예제 #13
0
파일: kdb_db2.c 프로젝트: DirectXMan12/krb5
/* Initialize dbc by locking and creating the DB.  If the DB already exists,
 * clear it out if dbc->tempdb is set; otherwise return EEXIST. */
static krb5_error_code
ctx_create_db(krb5_context context, krb5_db2_context *dbc)
{
    krb5_error_code retval = 0;
    char *dbname = NULL, *polname = NULL, *plockname = NULL;

    retval = ctx_allfiles(dbc, &dbname, &dbc->db_lf_name, &polname,
                          &plockname);
    if (retval)
        return retval;

    dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC,
                           0600);
    if (dbc->db_lf_file < 0) {
        retval = errno;
        goto cleanup;
    }
    retval = krb5_lock_file(context, dbc->db_lf_file,
                            KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
    if (retval != 0)
        goto cleanup;
    set_cloexec_fd(dbc->db_lf_file);
    dbc->db_lock_mode = KRB5_LOCKMODE_EXCLUSIVE;
    dbc->db_locks_held = 1;

    if (dbc->tempdb) {
        /* Temporary DBs are locked for their whole lifetime.  Since we have
         * the lock, any remnant files can be safely destroyed. */
        (void) destroy_file(dbname);
        (void) unlink(polname);
        (void) unlink(plockname);
    }

    dbc->db = open_db(dbc, O_RDWR | O_CREAT | O_EXCL, 0600);
    if (dbc->db == NULL) {
        retval = errno;
        goto cleanup;
    }

    /* Create the policy database, initialize a handle to it, and lock it. */
    retval = osa_adb_create_db(polname, plockname, OSA_ADB_POLICY_DB_MAGIC);
    if (retval)
        goto cleanup;
    retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
                             OSA_ADB_POLICY_DB_MAGIC);
    if (retval)
        goto cleanup;
    retval = osa_adb_get_lock(dbc->policy_db, KRB5_DB_LOCKMODE_EXCLUSIVE);
    if (retval)
        goto cleanup;

    dbc->db_inited = 1;

cleanup:
    if (retval) {
        if (dbc->db != NULL)
            dbc->db->close(dbc->db);
        if (dbc->db_locks_held > 0) {
            (void) krb5_lock_file(context, dbc->db_lf_file,
                                  KRB5_LOCKMODE_UNLOCK);
        }
        if (dbc->db_lf_file >= 0)
            close(dbc->db_lf_file);
        ctx_clear(dbc);
    }
    free(dbname);
    free(polname);
    free(plockname);
    return retval;
}
예제 #14
0
파일: svc_udp.c 프로젝트: PADL/krb5
/*
 * Usage:
 *	xprt = svcudp_create(sock);
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svcudp_create
 * binds it to an arbitrary port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 * Once *xprt is initialized, it is registered as a transporter;
 * see (svc.h, xprt_register).
 * The routines returns NULL if a problem occurred.
 */
SVCXPRT *
svcudp_bufcreate(
	int sock,
	u_int sendsz,
	u_int recvsz)
{
	bool_t madesock = FALSE;
	SVCXPRT *xprt;
	struct svcudp_data *su;
	struct sockaddr_storage ss;
	struct sockaddr *sa = (struct sockaddr *)&ss;
	socklen_t len;

	if (sock == RPC_ANYSOCK) {
		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
			perror("svcudp_create: socket creation problem");
			return ((SVCXPRT *)NULL);
		}
		set_cloexec_fd(sock);
		madesock = TRUE;
		memset(&ss, 0, sizeof(ss));
		sa->sa_family = AF_INET;
	} else {
		len = sizeof(struct sockaddr_storage);
		if (getsockname(sock, sa, &len) < 0) {
			perror("svcudp_create - cannot getsockname");
			return ((SVCXPRT *)NULL);
		}
	}

	if (bindresvport_sa(sock, sa)) {
		sa_setport(sa, 0);
		(void)bind(sock, sa, sa_socklen(sa));
	}
	len = sizeof(struct sockaddr_storage);
	if (getsockname(sock, sa, &len) != 0) {
		perror("svcudp_create - cannot getsockname");
		if (madesock)
			(void)close(sock);
		return ((SVCXPRT *)NULL);
	}
	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
	if (xprt == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	su = (struct svcudp_data *)mem_alloc(sizeof(*su));
	if (su == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
	if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	xdrmem_create(
	    &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
	su->su_cache = NULL;
	xprt->xp_p2 = (caddr_t)su;
	xprt->xp_auth = NULL;
	xprt->xp_verf.oa_base = su->su_verfbody;
	xprt->xp_ops = &svcudp_op;
	xprt->xp_port = sa_getport(sa);
	xprt->xp_sock = sock;
	xprt_register(xprt);
	return (xprt);
}
예제 #15
0
파일: cc_file.c 프로젝트: arkadiyg/krb5
/* Destroy the cache file and release the handle. */
static krb5_error_code KRB5_CALLCONV
fcc_destroy(krb5_context context, krb5_ccache id)
{
    krb5_error_code ret = 0;
    fcc_data *data = id->data;
    int st, fd;
    struct stat buf;
    unsigned long i, size;
    unsigned int wlen;
    char zeros[BUFSIZ];

    k5_cc_mutex_lock(context, &data->lock);

    if (OPENCLOSE(id)) {
        invalidate_cache(data);
        fd = THREEPARAMOPEN(data->filename, O_RDWR | O_BINARY, 0);
        if (fd < 0) {
            ret = interpret_errno(context, errno);
            goto cleanup;
        }
        set_cloexec_fd(fd);
        data->fd = fd;
    } else {
        fcc_lseek(data, 0, SEEK_SET);
    }

#ifdef MSDOS_FILESYSTEM
    /*
     * "Disgusting bit of UNIX trivia" - that's how the writers of NFS describe
     * the ability of UNIX to still write to a file which has been unlinked.
     * Naturally, the PC can't do this.  As a result, we have to delete the
     * file after we wipe it clean, but that throws off all the error handling
     * code.  So we have do the work ourselves.
     */
    st = fstat(data->fd, &buf);
    if (st == -1) {
        ret = interpret_errno(context, errno);
        size = 0;               /* Nothing to wipe clean */
    } else {
        size = (unsigned long)buf.st_size;
    }

    memset(zeros, 0, BUFSIZ);
    while (size > 0) {
        wlen = (int)((size > BUFSIZ) ? BUFSIZ : size); /* How much to write */
        i = write(data->fd, zeros, wlen);
        if (i < 0) {
            ret = interpret_errno(context, errno);
            /* Don't jump to cleanup--we still want to delete the file. */
            break;
        }
        size -= i;
    }

    if (OPENCLOSE(id)) {
        (void)close(((fcc_data *)id->data)->fd);
        data->fd = -1;
    }

    st = unlink(data->filename);
    if (st < 0) {
        ret = interpret_errno(context, errno);
        goto cleanup;
    }

#else /* MSDOS_FILESYSTEM */

    st = unlink(data->filename);
    if (st < 0) {
        ret = interpret_errno(context, errno);
        if (OPENCLOSE(id)) {
            (void)close(data->fd);
            data->fd = -1;
        }
        goto cleanup;
    }

    st = fstat(data->fd, &buf);
    if (st < 0) {
        ret = interpret_errno(context, errno);
        if (OPENCLOSE(id)) {
            (void)close(data->fd);
            data->fd = -1;
        }
        goto cleanup;
    }

    /* XXX This may not be legal XXX */
    size = (unsigned long)buf.st_size;
    memset(zeros, 0, BUFSIZ);
    for (i = 0; i < size / BUFSIZ; i++) {
        if (write(data->fd, zeros, BUFSIZ) < 0) {
            ret = interpret_errno(context, errno);
            if (OPENCLOSE(id)) {
                (void)close(data->fd);
                data->fd = -1;
            }
            goto cleanup;
        }
    }

    wlen = size % BUFSIZ;
    if (write(data->fd, zeros, wlen) < 0) {
        ret = interpret_errno(context, errno);
        if (OPENCLOSE(id)) {
            (void)close(data->fd);
            data->fd = -1;
        }
        goto cleanup;
    }

    st = close(data->fd);
    data->fd = -1;

    if (st)
        ret = interpret_errno(context, errno);

#endif /* MSDOS_FILESYSTEM */

cleanup:
    k5_cc_mutex_unlock(context, &data->lock);
    dereference(context, data);
    free(id);

    krb5_change_cache();
    return ret;
}
예제 #16
0
파일: kdb_db2.c 프로젝트: Brainiarc7/pbis
/*
 * "Atomically" rename the database in a way that locks out read
 * access in the middle of the rename.
 *
 * Not perfect; if we crash in the middle of an update, we don't
 * necessarily know to complete the transaction the rename, but...
 *
 * Since the rename operation happens outside the init/fini bracket, we
 * have to go through the same stuff that we went through up in db_destroy.
 */
krb5_error_code
krb5_db2_rename(krb5_context context, char *from, char *to, int merge_nra)
{
    char *fromok;
    krb5_error_code retval;
    krb5_db2_context *s_context, *db_ctx;
    kdb5_dal_handle *dal_handle = context->dal_handle;

    s_context = dal_handle->db_context;
    dal_handle->db_context = NULL;
    if ((retval = k5db2_init_context(context)))
        return retval;
    db_ctx = (krb5_db2_context *) dal_handle->db_context;

    /*
     * Create the database if it does not already exist; the
     * files must exist because krb5_db2_lock, called below,
     * will fail otherwise.
     */
    retval = create_db(context, to);
    if (retval != 0 && retval != EEXIST)
        goto errout;

    /*
     * Set the database to the target, so that other processes sharing
     * the target will stop their activity, and notice the new database.
     */
    db_ctx->db_name = strdup(to);
    if (db_ctx->db_name == NULL) {
        retval = ENOMEM;
        goto errout;
    }

    retval = check_openable(context);
    if (retval)
        goto errout;

    retval = krb5_db2_init(context);
    if (retval)
        goto errout;

    db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT);
    if (db_ctx->db_lf_name == NULL) {
        retval = ENOMEM;
        goto errout;
    }
    db_ctx->db_lf_file = open(db_ctx->db_lf_name, O_RDWR|O_CREAT, 0600);
    if (db_ctx->db_lf_file < 0) {
        retval = errno;
        goto errout;
    }
    set_cloexec_fd(db_ctx->db_lf_file);

    db_ctx->db_inited = 1;

    retval = krb5_db2_get_age(context, NULL, &db_ctx->db_lf_time);
    if (retval)
        goto errout;

    fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
    if (fromok == NULL) {
        retval = ENOMEM;
        goto errout;
    }

    if ((retval = krb5_db2_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
        goto errfromok;

    if ((retval = krb5_db2_start_update(context)))
        goto errfromok;

    if (merge_nra) {
        if ((retval = krb5_db2_begin_nra_merge(context, s_context, db_ctx)))
            goto errfromok;
    }

    if (rename(from, to)) {
        retval = errno;
        goto errfromok;
    }
    if (unlink(fromok)) {
        retval = errno;
        goto errfromok;
    }

    if (merge_nra) {
        krb5_db2_end_nra_merge(context, s_context, db_ctx);
    }

    retval = krb5_db2_end_update(context);
    if (retval)
        goto errfromok;

    {
        /* XXX moved so that NRA merge works */
        /* Ugly brute force hack.

           Should be going through nice friendly helper routines for
           this, but it's a mess of jumbled so-called interfaces right
           now.  */
        char    policy[2048], new_policy[2048];
        assert (strlen(db_ctx->db_name) < 2000);
        snprintf(policy, sizeof(policy), "%s.kadm5", db_ctx->db_name);
        snprintf(new_policy, sizeof(new_policy),
                 "%s~.kadm5", db_ctx->db_name);
        if (0 != rename(new_policy, policy)) {
            retval = errno;
            goto errfromok;
        }
        strlcat(new_policy, ".lock",sizeof(new_policy));
        (void) unlink(new_policy);
    }

errfromok:
    free_dbsuffix(fromok);
errout:
    if (dal_handle->db_context) {
        if (db_ctx->db_lf_file >= 0) {
            krb5_db2_unlock(context);
            close(db_ctx->db_lf_file);
        }
        k5db2_clear_context((krb5_db2_context *) dal_handle->db_context);
        free(dal_handle->db_context);
    }

    dal_handle->db_context = s_context;
    (void) krb5_db2_unlock(context); /* unlock saved context db */

    return retval;
}
예제 #17
0
/*
 * Usage:
 *	xprt = svcudp_create(sock);
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svcudp_create
 * binds it to an arbitrary port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 * Once *xprt is initialized, it is registered as a transporter;
 * see (svc.h, xprt_register).
 * The routines returns NULL if a problem occurred.
 */
SVCXPRT *
svcudp_bufcreate(
    register int sock,
    u_int sendsz,
    u_int recvsz)
{
    bool_t madesock = FALSE;
    register SVCXPRT *xprt;
    register struct svcudp_data *su;
    struct sockaddr_in addr;
    int len = sizeof(struct sockaddr_in);

    if (sock == RPC_ANYSOCK) {
        if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
            perror("svcudp_create: socket creation problem");
            return ((SVCXPRT *)NULL);
        }
        set_cloexec_fd(sock);
        madesock = TRUE;
    }
    memset(&addr, 0, sizeof (addr));
#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
    addr.sin_len = sizeof(addr);
#endif
    addr.sin_family = AF_INET;
    if (bindresvport(sock, &addr)) {
        addr.sin_port = 0;
        (void)bind(sock, (struct sockaddr *)&addr, len);
    }
    if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
        perror("svcudp_create - cannot getsockname");
        if (madesock)
            (void)close(sock);
        return ((SVCXPRT *)NULL);
    }
    xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
    if (xprt == NULL) {
        (void)fprintf(stderr, "svcudp_create: out of memory\n");
        return (NULL);
    }
    su = (struct svcudp_data *)mem_alloc(sizeof(*su));
    if (su == NULL) {
        (void)fprintf(stderr, "svcudp_create: out of memory\n");
        return (NULL);
    }
    su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
    if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
        (void)fprintf(stderr, "svcudp_create: out of memory\n");
        return (NULL);
    }
    xdrmem_create(
        &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
    su->su_cache = NULL;
    xprt->xp_p2 = (caddr_t)su;
    xprt->xp_auth = NULL;
    xprt->xp_verf.oa_base = su->su_verfbody;
    xprt->xp_ops = &svcudp_op;
    xprt->xp_port = ntohs(addr.sin_port);
    xprt->xp_sock = sock;
    xprt_register(xprt);
    return (xprt);
}
예제 #18
0
파일: pmap_rmt.c 프로젝트: PADL/krb5
enum clnt_stat
clnt_broadcast(
	rpcprog_t	prog,		/* program number */
	rpcvers_t	vers,		/* version number */
	rpcproc_t	proc,		/* procedure number */
	xdrproc_t	xargs,		/* xdr routine for args */
	caddr_t		argsp,		/* pointer to args */
	xdrproc_t	xresults,	/* xdr routine for results */
	caddr_t		resultsp,	/* pointer to results */
	resultproc_t	eachresult	/* call with each result obtained */
	)
{
	enum clnt_stat stat;
	AUTH *unix_auth = authunix_create_default();
	XDR xdr_stream;
	XDR *xdrs = &xdr_stream;
	int outlen, nets;
	ssize_t inlen;
	GETSOCKNAME_ARG3_TYPE fromlen;
        SOCKET sock;
	int on = 1;
#ifdef FD_SETSIZE
	fd_set mask;
	fd_set readfds;
#else
	int readfds;
	int mask;
#endif /* def FD_SETSIZE */
	int i;
	bool_t done = FALSE;
	uint32_t xid;
	rpcport_t port;
	struct in_addr addrs[20];
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
	struct rmtcallargs a;
	struct rmtcallres r;
	struct rpc_msg msg;
	struct timeval t, t2;
	char outbuf[MAX_BROADCAST_SIZE];
#ifndef MAX
#define MAX(A,B) ((A)<(B)?(B):(A))
#endif
	char inbuf[MAX (UDPMSGSIZE, GIFCONF_BUFSIZE)];

	/*
	 * initialization: create a socket, a broadcast address, and
	 * preserialize the arguments into a send buffer.
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		perror("Cannot create socket for broadcast rpc");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
	set_cloexec_fd(sock);
#ifdef SO_BROADCAST
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &on,
		       sizeof (on)) < 0) {
		perror("Cannot set socket option SO_BROADCAST");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#endif /* def SO_BROADCAST */
#ifdef FD_SETSIZE
	FD_ZERO(&mask);
	FD_SET(sock, &mask);
#else
	mask = (1 << sock);
#endif /* def FD_SETSIZE */
	nets = getbroadcastnets(addrs, sock, inbuf);
	memset(&baddr, 0, sizeof (baddr));
	baddr.sin_family = AF_INET;
	baddr.sin_port = htons(PMAPPORT);
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
	(void)gettimeofday(&t, (struct timezone *)0);
	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
	t.tv_usec = 0;
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = PMAPPROG;
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
	msg.rm_call.cb_cred = unix_auth->ah_cred;
	msg.rm_call.cb_verf = unix_auth->ah_verf;
	a.prog = prog;
	a.vers = vers;
	a.proc = proc;
	a.xdr_args = xargs;
	a.args_ptr = argsp;
	r.port_ptr = &port;
	r.xdr_results = xresults;
	r.results_ptr = resultsp;
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);
	/*
	 * Basic loop: broadcast a packet and wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 */
	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
		for (i = 0; i < nets; i++) {
			baddr.sin_addr = addrs[i];
			if (sendto(sock, outbuf, outlen, 0,
				(struct sockaddr *)&baddr,
				sizeof (struct sockaddr)) != outlen) {
				perror("Cannot send broadcast packet");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
		}
		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}
	recv_again:
		msg.acpted_rply.ar_verf = gssrpc__null_auth;
		msg.acpted_rply.ar_results.where = (caddr_t)&r;
                msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
		readfds = mask;
		t2 = t;
		switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set *)NULL,
			       (fd_set *)NULL, &t2)) {

		case 0:  /* timed out */
			stat = RPC_TIMEDOUT;
			continue;

		case -1:  /* some kind of error */
			if (errno == EINTR)
				goto recv_again;
			perror("Broadcast select problem");
			stat = RPC_CANTRECV;
			goto done_broad;

		}  /* end of select results switch */
	try_again:
		fromlen = sizeof(struct sockaddr);
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
			(struct sockaddr *)&raddr, &fromlen);
		if (inlen < 0) {
			if (errno == EINTR)
				goto try_again;
			perror("Cannot receive reply to broadcast");
			stat = RPC_CANTRECV;
			goto done_broad;
		}
		if ((size_t)inlen < sizeof(uint32_t))
			goto recv_again;
		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 */
		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
			if ((msg.rm_xid == xid) &&
				(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
				(msg.acpted_rply.ar_stat == SUCCESS)) {
				raddr.sin_port = htons((u_short)port);
				done = (*eachresult)(resultsp, &raddr);
			}
			/* otherwise, we just ignore the errors ... */
		} else {
#ifdef notdef
			/* some kind of deserialization problem ... */
			if (msg.rm_xid == xid)
				fprintf(stderr, "Broadcast deserialization problem");
			/* otherwise, just random garbage */
#endif
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = xdr_void;
		(void)xdr_replymsg(xdrs, &msg);
		(void)(*xresults)(xdrs, resultsp);
		xdr_destroy(xdrs);
		if (done) {
			stat = RPC_SUCCESS;
			goto done_broad;
		} else {
			goto recv_again;
		}
	}
done_broad:
        (void)closesocket(sock);
	AUTH_DESTROY(unix_auth);
	return (stat);
}
예제 #19
0
파일: sendto_kdc.c 프로젝트: Akasurde/krb5
static int
start_connection(krb5_context context, struct conn_state *state,
                 const krb5_data *message, struct select_state *selstate,
                 const krb5_data *realm,
                 struct sendto_callback_info *callback_info)
{
    int fd, e, type;
    static const int one = 1;
    static const struct linger lopt = { 0, 0 };

    type = socktype_for_transport(state->addr.transport);
    fd = socket(state->addr.family, type, 0);
    if (fd == INVALID_SOCKET)
        return -1;              /* try other hosts */
    set_cloexec_fd(fd);
    /* Make it non-blocking.  */
    ioctlsocket(fd, FIONBIO, (const void *) &one);
    if (state->addr.transport == TCP) {
        setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt));
        TRACE_SENDTO_KDC_TCP_CONNECT(context, &state->addr);
    }

    /* Start connecting to KDC.  */
    e = connect(fd, (struct sockaddr *)&state->addr.saddr, state->addr.len);
    if (e != 0) {
        /*
         * This is the path that should be followed for non-blocking
         * connections.
         */
        if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
            state->state = CONNECTING;
            state->fd = fd;
        } else {
            (void) closesocket(fd);
            state->state = FAILED;
            return -2;
        }
    } else {
        /*
         * Connect returned zero even though we made it non-blocking.  This
         * happens normally for UDP sockets, and can perhaps also happen for
         * TCP sockets connecting to localhost.
         */
        state->state = WRITING;
        state->fd = fd;
    }

    /*
     * Here's where KPASSWD callback gets the socket information it needs for
     * a kpasswd request
     */
    if (callback_info) {

        e = callback_info->pfn_callback(state->fd, callback_info->data,
                                        &state->callback_buffer);
        if (e != 0) {
            (void) closesocket(fd);
            state->fd = INVALID_SOCKET;
            state->state = FAILED;
            return -3;
        }

        message = &state->callback_buffer;
    }

    e = set_transport_message(state, realm, message);
    if (e != 0) {
        TRACE_SENDTO_KDC_ERROR_SET_MESSAGE(context, &state->addr, e);
        (void) closesocket(state->fd);
        state->fd = INVALID_SOCKET;
        state->state = FAILED;
        return -4;
    }

    if (state->addr.transport == UDP) {
        /* Send it now.  */
        ssize_t ret;
        sg_buf *sg = &state->out.sgbuf[0];

        TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, &state->addr);
        ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
        if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
            TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, &state->addr,
                                                    SOCKET_ERRNO);
            (void) closesocket(state->fd);
            state->fd = INVALID_SOCKET;
            state->state = FAILED;
            return -5;
        } else {
            state->state = READING;
        }
    }

    if (!cm_add_fd(selstate, state->fd)) {
        (void) closesocket(state->fd);
        state->fd = INVALID_SOCKET;
        state->state = FAILED;
        return -1;
    }
    if (state->state == CONNECTING || state->state == WRITING)
        cm_write(selstate, state->fd);
    else
        cm_read(selstate, state->fd);

    return 0;
}
예제 #20
0
static int
start_connection(krb5_context context, struct conn_state *state,
                 struct select_state *selstate,
                 struct sendto_callback_info *callback_info)
{
    int fd, e;

    dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
           state->socktype == SOCK_STREAM ? "stream" : "dgram", state->family);
    fd = socket(state->family, state->socktype, 0);
    if (fd == INVALID_SOCKET) {
        state->err = SOCKET_ERRNO;
        dprint("socket: %m creating with af %d\n", state->err, state->family);
        return -1;              /* try other hosts */
    }
#ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value.  */
    if (fd >= FD_SETSIZE) {
        closesocket(fd);
        state->err = EMFILE;
        dprint("socket: fd %d too high\n", fd);
        return -1;
    }
#endif
    set_cloexec_fd(fd);
    /* Make it non-blocking.  */
    if (state->socktype == SOCK_STREAM) {
        static const int one = 1;
        static const struct linger lopt = { 0, 0 };

        if (ioctlsocket(fd, FIONBIO, (const void *) &one))
            dperror("sendto_kdc: ioctl(FIONBIO)");
        if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)))
            dperror("sendto_kdc: setsockopt(SO_LINGER)");
        TRACE_SENDTO_KDC_TCP_CONNECT(context, state);
    }

    /* Start connecting to KDC.  */
    e = connect(fd, (struct sockaddr *)&state->addr, state->addrlen);
    if (e != 0) {
        /*
         * This is the path that should be followed for non-blocking
         * connections.
         */
        if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
            state->state = CONNECTING;
            state->fd = fd;
        } else {
            dprint("connect failed: %m\n", SOCKET_ERRNO);
            (void) closesocket(fd);
            state->err = SOCKET_ERRNO;
            state->state = FAILED;
            return -2;
        }
    } else {
        /*
         * Connect returned zero even though we made it non-blocking.  This
         * happens normally for UDP sockets, and can perhaps also happen for
         * TCP sockets connecting to localhost.
         */
        state->state = WRITING;
        state->fd = fd;
    }
    dprint("new state = %s\n", state_strings[state->state]);


    /*
     * Here's where KPASSWD callback gets the socket information it needs for
     * a kpasswd request
     */
    if (callback_info) {

        e = callback_info->pfn_callback(state, callback_info->context,
                                        &state->callback_buffer);
        if (e != 0) {
            dprint("callback failed: %m\n", e);
            (void) closesocket(fd);
            state->err = e;
            state->fd = INVALID_SOCKET;
            state->state = FAILED;
            return -3;
        }

        set_conn_state_msg_length(state, &state->callback_buffer);
    }

    if (state->socktype == SOCK_DGRAM) {
        /* Send it now.  */
        ssize_t ret;
        sg_buf *sg = &state->x.out.sgbuf[0];

        TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, state);
        dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd);
        ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
        if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
            TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, state,
                                                    SOCKET_ERRNO);
            dperror("sendto");
            (void) closesocket(state->fd);
            state->fd = INVALID_SOCKET;
            state->state = FAILED;
            return -4;
        } else {
            state->state = READING;
        }
    }
    FD_SET(state->fd, &selstate->rfds);
    if (state->state == CONNECTING || state->state == WRITING)
        FD_SET(state->fd, &selstate->wfds);
    FD_SET(state->fd, &selstate->xfds);
    if (selstate->max <= state->fd)
        selstate->max = state->fd + 1;
    selstate->nfds++;

    dprint("new select vectors: %F\n",
           &selstate->rfds, &selstate->wfds, &selstate->xfds, selstate->max);

    return 0;
}