int rnd_ioctl(struct file *fp, u_long cmd, void *addr) { krndsource_t *kr; rndstat_t *rst; rndstat_name_t *rstnm; rndctl_t *rctl; rnddata_t *rnddata; u_int32_t count, start; int ret = 0; int estimate_ok = 0, estimate = 0; switch (cmd) { case FIONBIO: case FIOASYNC: case RNDGETENTCNT: break; case RNDGETPOOLSTAT: case RNDGETSRCNUM: case RNDGETSRCNAME: ret = kauth_authorize_device(curlwp->l_cred, KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL); if (ret) return (ret); break; case RNDCTL: ret = kauth_authorize_device(curlwp->l_cred, KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL); if (ret) return (ret); break; case RNDADDDATA: ret = kauth_authorize_device(curlwp->l_cred, KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); if (ret) return (ret); estimate_ok = !kauth_authorize_device(curlwp->l_cred, KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); break; default: #ifdef COMPAT_50 return compat_50_rnd_ioctl(fp, cmd, addr); #else return ENOTTY; #endif } switch (cmd) { /* * Handled in upper layer really, but we have to return zero * for it to be accepted by the upper layer. */ case FIONBIO: case FIOASYNC: break; case RNDGETENTCNT: mutex_spin_enter(&rndpool_mtx); *(u_int32_t *)addr = rndpool_get_entropy_count(&rnd_pool); mutex_spin_exit(&rndpool_mtx); break; case RNDGETPOOLSTAT: mutex_spin_enter(&rndpool_mtx); rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t)); mutex_spin_exit(&rndpool_mtx); break; case RNDGETSRCNUM: rst = (rndstat_t *)addr; if (rst->count == 0) break; if (rst->count > RND_MAXSTATCOUNT) return (EINVAL); mutex_spin_enter(&rndpool_mtx); /* * Find the starting source by running through the * list of sources. */ kr = rnd_sources.lh_first; start = rst->start; while (kr != NULL && start >= 1) { kr = kr->list.le_next; start--; } /* * Return up to as many structures as the user asked * for. If we run out of sources, a count of zero * will be returned, without an error. */ for (count = 0; count < rst->count && kr != NULL; count++) { krndsource_to_rndsource(kr, &rst->source[count]); kr = kr->list.le_next; } rst->count = count; mutex_spin_exit(&rndpool_mtx); break; case RNDGETSRCNAME: /* * Scan through the list, trying to find the name. */ mutex_spin_enter(&rndpool_mtx); rstnm = (rndstat_name_t *)addr; kr = rnd_sources.lh_first; while (kr != NULL) { if (strncmp(kr->name, rstnm->name, MIN(sizeof(kr->name), sizeof(*rstnm))) == 0) { krndsource_to_rndsource(kr, &rstnm->source); mutex_spin_exit(&rndpool_mtx); return (0); } kr = kr->list.le_next; } mutex_spin_exit(&rndpool_mtx); ret = ENOENT; /* name not found */ break; case RNDCTL: /* * Set flags to enable/disable entropy counting and/or * collection. */ mutex_spin_enter(&rndpool_mtx); rctl = (rndctl_t *)addr; kr = rnd_sources.lh_first; /* * Flags set apply to all sources of this type. */ if (rctl->type != 0xff) { while (kr != NULL) { if (kr->type == rctl->type) { kr->flags &= ~rctl->mask; kr->flags |= (rctl->flags & rctl->mask); } kr = kr->list.le_next; } mutex_spin_exit(&rndpool_mtx); return (0); } /* * scan through the list, trying to find the name */ while (kr != NULL) { if (strncmp(kr->name, rctl->name, MIN(sizeof(kr->name), sizeof(rctl->name))) == 0) { kr->flags &= ~rctl->mask; kr->flags |= (rctl->flags & rctl->mask); mutex_spin_exit(&rndpool_mtx); return (0); } kr = kr->list.le_next; } mutex_spin_exit(&rndpool_mtx); ret = ENOENT; /* name not found */ break; case RNDADDDATA: /* * Don't seed twice if our bootloader has * seed loading support. */ if (!boot_rsp) { rnddata = (rnddata_t *)addr; if (rnddata->len > sizeof(rnddata->data)) return EINVAL; if (estimate_ok) { /* * Do not accept absurd entropy estimates, and * do not flood the pool with entropy such that * new samples are discarded henceforth. */ estimate = MIN((rnddata->len * NBBY) / 2, MIN(rnddata->entropy, RND_POOLBITS / 2)); } else { estimate = 0; } mutex_spin_enter(&rndpool_mtx); rndpool_add_data(&rnd_pool, rnddata->data, rnddata->len, estimate); mutex_spin_exit(&rndpool_mtx); rnd_wakeup_readers(); } #ifdef RND_VERBOSE else { printf("rnd: already seeded by boot loader\n"); } #endif break; default: return ENOTTY; } return (ret); }
/* * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode. * Some of these have no real effect in raw mode, however. */ static int wskbd_displayioctl(device_t dev, u_long cmd, void *data, int flag, struct lwp *l) { #ifdef WSDISPLAY_SCROLLSUPPORT struct wskbd_scroll_data *usdp, *ksdp; #endif struct wskbd_softc *sc = device_private(dev); struct wskbd_bell_data *ubdp, *kbdp; struct wskbd_keyrepeat_data *ukdp, *kkdp; struct wskbd_map_data *umdp; struct wskbd_mapdata md; kbd_t enc; void *tbuf; int len, error; switch (cmd) { #define SETBELL(dstp, srcp, dfltp) \ do { \ (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \ (srcp)->pitch : (dfltp)->pitch; \ (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \ (srcp)->period : (dfltp)->period; \ (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \ (srcp)->volume : (dfltp)->volume; \ (dstp)->which = WSKBD_BELL_DOALL; \ } while (0) case WSKBDIO_BELL: if ((flag & FWRITE) == 0) return (EACCES); return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, WSKBDIO_COMPLEXBELL, (void *)&sc->sc_bell_data, flag, l)); case WSKBDIO_COMPLEXBELL: if ((flag & FWRITE) == 0) return (EACCES); ubdp = (struct wskbd_bell_data *)data; SETBELL(ubdp, ubdp, &sc->sc_bell_data); return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, WSKBDIO_COMPLEXBELL, (void *)ubdp, flag, l)); case WSKBDIO_SETBELL: if ((flag & FWRITE) == 0) return (EACCES); kbdp = &sc->sc_bell_data; setbell: ubdp = (struct wskbd_bell_data *)data; SETBELL(kbdp, ubdp, kbdp); return (0); case WSKBDIO_GETBELL: kbdp = &sc->sc_bell_data; getbell: ubdp = (struct wskbd_bell_data *)data; SETBELL(ubdp, kbdp, kbdp); return (0); case WSKBDIO_SETDEFAULTBELL: if ((error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_WSCONS_KEYBOARD_BELL, NULL, NULL, NULL, NULL)) != 0) return (error); kbdp = &wskbd_default_bell_data; goto setbell; case WSKBDIO_GETDEFAULTBELL: kbdp = &wskbd_default_bell_data; goto getbell; #undef SETBELL #define SETKEYREPEAT(dstp, srcp, dfltp) \ do { \ (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \ (srcp)->del1 : (dfltp)->del1; \ (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \ (srcp)->delN : (dfltp)->delN; \ (dstp)->which = WSKBD_KEYREPEAT_DOALL; \ } while (0) case WSKBDIO_SETKEYREPEAT: if ((flag & FWRITE) == 0) return (EACCES); kkdp = &sc->sc_keyrepeat_data; setkeyrepeat: ukdp = (struct wskbd_keyrepeat_data *)data; SETKEYREPEAT(kkdp, ukdp, kkdp); return (0); case WSKBDIO_GETKEYREPEAT: kkdp = &sc->sc_keyrepeat_data; getkeyrepeat: ukdp = (struct wskbd_keyrepeat_data *)data; SETKEYREPEAT(ukdp, kkdp, kkdp); return (0); case WSKBDIO_SETDEFAULTKEYREPEAT: if ((error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_WSCONS_KEYBOARD_KEYREPEAT, NULL, NULL, NULL, NULL)) != 0) return (error); kkdp = &wskbd_default_keyrepeat_data; goto setkeyrepeat; case WSKBDIO_GETDEFAULTKEYREPEAT: kkdp = &wskbd_default_keyrepeat_data; goto getkeyrepeat; #ifdef WSDISPLAY_SCROLLSUPPORT #define SETSCROLLMOD(dstp, srcp, dfltp) \ do { \ (dstp)->mode = ((srcp)->which & WSKBD_SCROLL_DOMODE) ? \ (srcp)->mode : (dfltp)->mode; \ (dstp)->modifier = ((srcp)->which & WSKBD_SCROLL_DOMODIFIER) ? \ (srcp)->modifier : (dfltp)->modifier; \ (dstp)->which = WSKBD_SCROLL_DOALL; \ } while (0) case WSKBDIO_SETSCROLL: usdp = (struct wskbd_scroll_data *)data; ksdp = &sc->sc_scroll_data; SETSCROLLMOD(ksdp, usdp, ksdp); return (0); case WSKBDIO_GETSCROLL: usdp = (struct wskbd_scroll_data *)data; ksdp = &sc->sc_scroll_data; SETSCROLLMOD(usdp, ksdp, ksdp); return (0); #else case WSKBDIO_GETSCROLL: case WSKBDIO_SETSCROLL: return ENODEV; #endif #undef SETKEYREPEAT case WSKBDIO_SETMAP: if ((flag & FWRITE) == 0) return (EACCES); umdp = (struct wskbd_map_data *)data; if (umdp->maplen > WSKBDIO_MAXMAPLEN) return (EINVAL); len = umdp->maplen*sizeof(struct wscons_keymap); tbuf = malloc(len, M_TEMP, M_WAITOK); error = copyin(umdp->map, tbuf, len); if (error == 0) { wskbd_init_keymap(umdp->maplen, &sc->sc_map, &sc->sc_maplen); memcpy(sc->sc_map, tbuf, len); /* drop the variant bits handled by the map */ sc->sc_layout = KB_USER | (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD); wskbd_update_layout(sc->id, sc->sc_layout); } free(tbuf, M_TEMP); return(error); case WSKBDIO_GETMAP: umdp = (struct wskbd_map_data *)data; if (umdp->maplen > sc->sc_maplen) umdp->maplen = sc->sc_maplen; error = copyout(sc->sc_map, umdp->map, umdp->maplen*sizeof(struct wscons_keymap)); return(error); case WSKBDIO_GETENCODING: *((kbd_t *) data) = sc->sc_layout; return(0); case WSKBDIO_SETENCODING: if ((flag & FWRITE) == 0) return (EACCES); enc = *((kbd_t *)data); if (KB_ENCODING(enc) == KB_USER) { /* user map must already be loaded */ if (KB_ENCODING(sc->sc_layout) != KB_USER) return (EINVAL); /* map variants make no sense */ if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD) return (EINVAL); } else { md = *(sc->id->t_keymap); /* structure assignment */ md.layout = enc; error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen); if (error) return (error); } sc->sc_layout = enc; wskbd_update_layout(sc->id, enc); return (0); case WSKBDIO_SETVERSION: return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); } /* * Try the keyboard driver for WSKBDIO ioctls. It returns -1 * if it didn't recognize the request, and in turn we return * -1 if we didn't recognize the request. */ /* printf("kbdaccess\n"); */ error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, flag, l); #ifdef WSDISPLAY_COMPAT_RAWKBD if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) { int s = spltty(); sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R | MOD_CONTROL_L | MOD_CONTROL_R | MOD_META_L | MOD_META_R | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2); if (sc->sc_repeating) { sc->sc_repeating = 0; callout_stop(&sc->sc_repeat_ch); } splx(s); } #endif return (error); }
static int rnd_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, int flags) { u_int8_t *bf; int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0; ret = kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); if (ret) { return (ret); } estimate_ok = !kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); DPRINTF(RND_DEBUG_WRITE, ("Random: Write of %zu requested\n", uio->uio_resid)); if (uio->uio_resid == 0) return (0); ret = 0; bf = pool_cache_get(rnd_temp_buffer_cache, PR_WAITOK); while (uio->uio_resid > 0) { /* * Don't flood the pool. */ if (added > RND_POOLWORDS * sizeof(int)) { #ifdef RND_VERBOSE printf("rnd: added %d already, adding no more.\n", added); #endif break; } n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid); ret = uiomove((void *)bf, n, uio); if (ret != 0) break; if (estimate_ok) { /* * Don't cause samples to be discarded by taking * the pool's entropy estimate to the max. */ if (added > RND_POOLWORDS / 2) estimate = 0; else estimate = n * NBBY / 2; #ifdef RND_VERBOSE printf("rnd: adding on write, %d bytes, estimate %d\n", n, estimate); #endif } else { #ifdef RND_VERBOSE printf("rnd: kauth says no entropy.\n"); #endif } /* * Mix in the bytes. */ mutex_spin_enter(&rndpool_mtx); rndpool_add_data(&rnd_pool, bf, n, estimate); mutex_spin_exit(&rndpool_mtx); added += n; DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n)); } pool_cache_put(rnd_temp_buffer_cache, bf); return (ret); }