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; }
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]); } }
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; }
/* * 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; }
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; }
/* 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; }
/* * 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); }
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 }
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; }
/* 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; }
/* * 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); }
/* 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; }
/* * 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); }
/* 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; }
/* * "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; }
/* * 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); }
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); }
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; }
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; }