lobase

Linux port of OpenBSDs userland.
Log | Files | Refs | README

commit fd5af0336a48185f86ab77e94ce1c9ec9ef14e9a
parent d57ddb5fa408a448989d9bb2576b3e2278587768
Author: Duncaen <mail@duncano.de>
Date:   Thu,  9 Mar 2017 04:16:43 +0100

lib/liboutil: renamed from libutil

Diffstat:
bin/date/Makefile | 2+-
bin/df/Makefile | 2+-
bin/ls/Makefile | 2+-
include/compat.h | 3+++
include/imsg.h | 4++--
include/ohash.h | 4++--
include/util.h | 4++--
lib/Makefile | 2+-
lib/liboutil/Makefile | 35+++++++++++++++++++++++++++++++++++
lib/liboutil/bcrypt_pbkdf.3 | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/bcrypt_pbkdf.c | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/check_expire.3 | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/check_expire.c | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/fmt_scaled.3 | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/fmt_scaled.c | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/fparseln.3 | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/fparseln.c | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/imsg-buffer.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/imsg.c | 302++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/imsg.h | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/imsg_init.3 | 550+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/isduid.3 | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/logwtmp.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/ohash.c | 327+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/ohash.h | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/ohash_init.3 | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/ohash_interval.3 | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/pidfile.3 | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/pidfile.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/pkcs5_pbkdf2.3 | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/pkcs5_pbkdf2.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/readlabel.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/readlabelfs.3 | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/shlib_version | 2++
lib/liboutil/util.h | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/uucplock.3 | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/liboutil/uucplock.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/libutil/Makefile | 35-----------------------------------
lib/libutil/bcrypt_pbkdf.3 | 69---------------------------------------------------------------------
lib/libutil/bcrypt_pbkdf.c | 169-------------------------------------------------------------------------------
lib/libutil/check_expire.3 | 62--------------------------------------------------------------
lib/libutil/check_expire.c | 189-------------------------------------------------------------------------------
lib/libutil/fmt_scaled.3 | 134-------------------------------------------------------------------------------
lib/libutil/fmt_scaled.c | 271-------------------------------------------------------------------------------
lib/libutil/fparseln.3 | 144-------------------------------------------------------------------------------
lib/libutil/fparseln.c | 208-------------------------------------------------------------------------------
lib/libutil/imsg-buffer.c | 309-------------------------------------------------------------------------------
lib/libutil/imsg.c | 302------------------------------------------------------------------------------
lib/libutil/imsg.h | 112-------------------------------------------------------------------------------
lib/libutil/imsg_init.3 | 550-------------------------------------------------------------------------------
lib/libutil/isduid.3 | 61-------------------------------------------------------------
lib/libutil/logwtmp.c | 65-----------------------------------------------------------------
lib/libutil/ohash.c | 327-------------------------------------------------------------------------------
lib/libutil/ohash.h | 74--------------------------------------------------------------------------
lib/libutil/ohash_init.3 | 271-------------------------------------------------------------------------------
lib/libutil/ohash_interval.3 | 93-------------------------------------------------------------------------------
lib/libutil/pidfile.3 | 82-------------------------------------------------------------------------------
lib/libutil/pidfile.c | 105-------------------------------------------------------------------------------
lib/libutil/pkcs5_pbkdf2.3 | 63---------------------------------------------------------------
lib/libutil/pkcs5_pbkdf2.c | 122-------------------------------------------------------------------------------
lib/libutil/readlabel.c | 144-------------------------------------------------------------------------------
lib/libutil/readlabelfs.3 | 61-------------------------------------------------------------
lib/libutil/shlib_version | 2--
lib/libutil/util.h | 91-------------------------------------------------------------------------------
lib/libutil/uucplock.3 | 178-------------------------------------------------------------------------------
lib/libutil/uucplock.c | 225-------------------------------------------------------------------------------
mk/bsd.prog.mk | 6+++---
usr.bin/du/Makefile | 2+-
usr.bin/file/Makefile | 2+-
usr.bin/sdiff/Makefile | 2+-
usr.bin/tsort/Makefile | 2+-
usr.bin/wc/Makefile | 2+-
usr.sbin/rdate/Makefile | 2+-
73 files changed, 4540 insertions(+), 4537 deletions(-)

diff --git a/bin/date/Makefile b/bin/date/Makefile @@ -5,6 +5,6 @@ PROG= date SRCS= date.c DPADD+= ${LIBUTIL} -LDADD+= -lutil +LDADD+= -loutil include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/bin/df/Makefile b/bin/df/Makefile @@ -4,7 +4,7 @@ PROG= df SRCS= df.c -LDADD= -lutil +LDADD= -loutil DPADD= ${LIBUTIL} include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/bin/ls/Makefile b/bin/ls/Makefile @@ -5,7 +5,7 @@ PROG= ls SRCS= cmp.c ls.c main.c print.c util.c utf8.c DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD= -loutil CPPFLAGS+=-D_GNU_SOURCE include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/include/compat.h b/include/compat.h @@ -144,6 +144,9 @@ uintmax_t strtoumax(const char *, char **, int); #define SHA512_Init SHA512Init #define SHA512_Final SHA512Final +/* sys/socket.h */ +#define RT_TABLEID_MAX 255 + /* sys/syslimits.h */ #define CHILD_MAX 80 /* max simultaneous processes */ diff --git a/include/imsg.h b/include/imsg.h @@ -1 +1 @@ -../lib/libutil/imsg.h- \ No newline at end of file +../lib/liboutil/imsg.h+ \ No newline at end of file diff --git a/include/ohash.h b/include/ohash.h @@ -1 +1 @@ -../lib/libutil/ohash.h- \ No newline at end of file +../lib/liboutil/ohash.h+ \ No newline at end of file diff --git a/include/util.h b/include/util.h @@ -1 +1 @@ -../lib/libutil/util.h- \ No newline at end of file +../lib/liboutil/util.h+ \ No newline at end of file diff --git a/lib/Makefile b/lib/Makefile @@ -1,3 +1,3 @@ TOPDIR?=.. -SUBDIR= libopenbsd libutil +SUBDIR= libopenbsd liboutil include ${.TOPDIR}/mk/bsd.subdir.mk diff --git a/lib/liboutil/Makefile b/lib/liboutil/Makefile @@ -0,0 +1,35 @@ +# $OpenBSD: Makefile,v 1.39 2016/03/30 06:38:43 jmc Exp $ +# $NetBSD: Makefile,v 1.8 1996/05/16 07:03:28 thorpej Exp $ + +.TOPDIR?=../.. +.CURDIR?=. + +LIB= outil +CPPFLAGS+=-D_GNU_SOURCE + +HDRS= util.h imsg.h +SRCS= bcrypt_pbkdf.c \ + logwtmp.c \ + uucplock.c fparseln.c pidfile.c \ + fmt_scaled.c imsg.c imsg-buffer.c pkcs5_pbkdf2.c + +MAN= bcrypt_pbkdf.3 \ + uucplock.3 \ + fparseln.3 pidfile.3 fmt_scaled.3 imsg_init.3 \ + pkcs5_pbkdf2.3 + +SRCS+= ohash.c +HDRS += ohash.h + +MAN += ohash_init.3 ohash_interval.3 + +includes: + @cd ${.CURDIR}; for i in $(HDRS); do \ + j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \ + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} \ + -m 444 $$i ${DESTDIR}/usr/include"; \ + echo $$j; \ + eval "$$j"; \ + done + +include ${.TOPDIR}/mk/bsd.lib.mk diff --git a/lib/liboutil/bcrypt_pbkdf.3 b/lib/liboutil/bcrypt_pbkdf.3 @@ -0,0 +1,69 @@ +.\" $OpenBSD: bcrypt_pbkdf.3,v 1.6 2014/11/25 03:37:12 tedu Exp $ +.\" +.\" Copyright (c) 2012 Ted Unangst <tedu@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: November 25 2014 $ +.Dt BCRYPT_PBKDF 3 +.Os +.Sh NAME +.Nm bcrypt_pbkdf +.Nd bcrypt password-based key derivation function +.Sh SYNOPSIS +.In util.h +.Ft int +.Fn bcrypt_pbkdf "const char *pass" "size_t pass_len" "const uint8_t *salt" \ + "size_t salt_len" "uint8_t *key" "size_t key_len" "unsigned int rounds" +.Sh DESCRIPTION +The +.Nm +function converts a password into a byte array suitable for use as +an encryption key. +The password and salt values are combined and repeatedly hashed +.Ar rounds +times. +The salt value should be randomly generated beforehand. +The repeated hashing is designed to thwart discovery of the key via +password guessing attacks. +The higher the number of rounds, the slower each attempt will be. +.\" A minimum value of at least 4 is recommended. +.Sh RETURN VALUES +The +.Fn bcrypt_pbkdf +function returns 0 to indicate success and \-1 for failure. +.\" .Sh EXAMPLES +.\" .Sh ERRORS +.Sh SEE ALSO +.Xr bcrypt 3 +.Sh STANDARDS +.Rs +.%A Niels Provos and David Mazieres +.%D June 1999 +.%T A Future-Adaptable Password Scheme +.Re +.Pp +.Rs +.%A B. Kaliski +.%D September 2000 +.%R RFC 2898 +.%T PKCS #5: Password-Based Cryptography Specification Version 2.0 +.Re +.\" .Sh HISTORY +.\" .Sh AUTHORS +.Sh CAVEATS +This implementation deviates slightly from the PBKDF2 standard by mixing +output key bits nonlinearly. +By mixing the output bytes together, an attacker is required to perform +all of the work without taking any shortcuts. +.\" .Sh BUGS diff --git a/lib/liboutil/bcrypt_pbkdf.c b/lib/liboutil/bcrypt_pbkdf.c @@ -0,0 +1,169 @@ +/* $OpenBSD: bcrypt_pbkdf.c,v 1.13 2015/01/12 03:20:04 tedu Exp $ */ +/* + * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdint.h> +#include <stdlib.h> +#include <blf.h> +#include <sha2.h> +#include <string.h> +#include <util.h> + +#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) + +/* + * pkcs #5 pbkdf2 implementation using the "bcrypt" hash + * + * The bcrypt hash function is derived from the bcrypt password hashing + * function with the following modifications: + * 1. The input password and salt are preprocessed with SHA512. + * 2. The output length is expanded to 256 bits. + * 3. Subsequently the magic string to be encrypted is lengthened and modifed + * to "OxychromaticBlowfishSwatDynamite" + * 4. The hash function is defined to perform 64 rounds of initial state + * expansion. (More rounds are performed by iterating the hash.) + * + * Note that this implementation pulls the SHA512 operations into the caller + * as a performance optimization. + * + * One modification from official pbkdf2. Instead of outputting key material + * linearly, we mix it. pbkdf2 has a known weakness where if one uses it to + * generate (e.g.) 512 bits of key material for use as two 256 bit keys, an + * attacker can merely run once through the outer loop, but the user + * always runs it twice. Shuffling output bytes requires computing the + * entirety of the key material to assemble any subkey. This is something a + * wise caller could do; we just do it for you. + */ + +#define BCRYPT_WORDS 8 +#define BCRYPT_HASHSIZE (BCRYPT_WORDS * 4) + +static void +bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) +{ + blf_ctx state; + uint8_t ciphertext[BCRYPT_HASHSIZE] = + "OxychromaticBlowfishSwatDynamite"; + uint32_t cdata[BCRYPT_WORDS]; + int i; + uint16_t j; + size_t shalen = SHA512_DIGEST_LENGTH; + + /* key expansion */ + Blowfish_initstate(&state); + Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen); + for (i = 0; i < 64; i++) { + Blowfish_expand0state(&state, sha2salt, shalen); + Blowfish_expand0state(&state, sha2pass, shalen); + } + + /* encryption */ + j = 0; + for (i = 0; i < BCRYPT_WORDS; i++) + cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), + &j); + for (i = 0; i < 64; i++) + blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); + + /* copy out */ + for (i = 0; i < BCRYPT_WORDS; i++) { + out[4 * i + 3] = (cdata[i] >> 24) & 0xff; + out[4 * i + 2] = (cdata[i] >> 16) & 0xff; + out[4 * i + 1] = (cdata[i] >> 8) & 0xff; + out[4 * i + 0] = cdata[i] & 0xff; + } + + /* zap */ + explicit_bzero(ciphertext, sizeof(ciphertext)); + explicit_bzero(cdata, sizeof(cdata)); + explicit_bzero(&state, sizeof(state)); +} + +int +bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, + uint8_t *key, size_t keylen, unsigned int rounds) +{ + SHA2_CTX ctx; + uint8_t sha2pass[SHA512_DIGEST_LENGTH]; + uint8_t sha2salt[SHA512_DIGEST_LENGTH]; + uint8_t out[BCRYPT_HASHSIZE]; + uint8_t tmpout[BCRYPT_HASHSIZE]; + uint8_t countsalt[4]; + size_t i, j, amt, stride; + uint32_t count; + size_t origkeylen = keylen; + + /* nothing crazy */ + if (rounds < 1) + return -1; + if (passlen == 0 || saltlen == 0 || keylen == 0 || + keylen > sizeof(out) * sizeof(out)) + return -1; + stride = (keylen + sizeof(out) - 1) / sizeof(out); + amt = (keylen + stride - 1) / stride; + + /* collapse password */ + SHA512Init(&ctx); + SHA512Update(&ctx, pass, passlen); + SHA512Final(sha2pass, &ctx); + + + /* generate key, sizeof(out) at a time */ + for (count = 1; keylen > 0; count++) { + countsalt[0] = (count >> 24) & 0xff; + countsalt[1] = (count >> 16) & 0xff; + countsalt[2] = (count >> 8) & 0xff; + countsalt[3] = count & 0xff; + + /* first round, salt is salt */ + SHA512Init(&ctx); + SHA512Update(&ctx, salt, saltlen); + SHA512Update(&ctx, countsalt, sizeof(countsalt)); + SHA512Final(sha2salt, &ctx); + bcrypt_hash(sha2pass, sha2salt, tmpout); + memcpy(out, tmpout, sizeof(out)); + + for (i = 1; i < rounds; i++) { + /* subsequent rounds, salt is previous output */ + SHA512Init(&ctx); + SHA512Update(&ctx, tmpout, sizeof(tmpout)); + SHA512Final(sha2salt, &ctx); + bcrypt_hash(sha2pass, sha2salt, tmpout); + for (j = 0; j < sizeof(out); j++) + out[j] ^= tmpout[j]; + } + + /* + * pbkdf2 deviation: output the key material non-linearly. + */ + amt = MINIMUM(amt, keylen); + for (i = 0; i < amt; i++) { + size_t dest = i * stride + (count - 1); + if (dest >= origkeylen) + break; + key[dest] = out[i]; + } + keylen -= i; + } + + /* zap */ + explicit_bzero(&ctx, sizeof(ctx)); + explicit_bzero(out, sizeof(out)); + + return 0; +} diff --git a/lib/liboutil/check_expire.3 b/lib/liboutil/check_expire.3 @@ -0,0 +1,62 @@ +.\" $OpenBSD: check_expire.3,v 1.10 2014/12/04 18:25:46 schwarze Exp $ +.\" +.\" Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 4 2014 $ +.Dt LOGIN_CHECK_EXPIRE 3 +.Os +.Sh NAME +.Nm login_check_expire +.Nd check for password expiration +.Sh SYNOPSIS +.In stdio.h +.In util.h +.Ft int +.Fn login_check_expire "FILE *back" "struct passwd *pwd" "char *class" "int lastchance" +.Sh DESCRIPTION +The +.Fn login_check_expire +function is called by a +.Bx +Authentication login script to +check whether the user's password entry, as described by +.Fa pwd , +has expired. +.Pp +If a +.Fa class +is specified, it is used instead of the class specified in the user's +password database entry. +If the +.Fa lastchance +argument is non-zero, the user's password has expired, and it has not been +expired longer than +.Dq password-dead +seconds (see +.Xr login.conf 5 ) , +the user will be able to log in one last time to change the password. +.Sh RETURN VALUES +The +.Fn login_check_expire +function returns 0 if the user's password has not expired, and 1 if it has +expired or if an error occurred. +.br +Status and error messages are passed +back to the login script caller via the back channel, +.Fa back . +.Sh SEE ALSO +.Xr auth_subr 3 , +.Xr authenticate 3 , +.Xr login.conf 5 diff --git a/lib/liboutil/check_expire.c b/lib/liboutil/check_expire.c @@ -0,0 +1,189 @@ +/* $OpenBSD: check_expire.c,v 1.12 2015/11/26 23:32:52 millert Exp $ */ + +/* + * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Berkeley Software Design, + * Inc. + * 4. The name of Berkeley Software Design, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI $From: check_expire.c,v 2.1 1997/08/08 18:38:25 prb Exp $ + */ + +#include <sys/types.h> + +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <login_cap.h> +#include <bsd_auth.h> + +#include "util.h" + +static char *pwd_update(const struct passwd *, const struct passwd *); + +#define SECSPERDAY (24 * 60 * 60) +#define TWOWEEKS (2 * 7 * SECSPERDAY) + +int +login_check_expire(FILE *back, struct passwd *pwd, char *class, int lastchance) +{ + auth_session_t *as; + login_cap_t *lc; + quad_t dead, expire, warn; + char *p; + + if ((as = auth_open()) == NULL) { + fprintf(back, BI_VALUE + " errormsg Unable to create auth session\n"); + fprintf(back, BI_REJECT "\n"); + return (1); + } + if (auth_setpwd(as, pwd) < 0) { + fprintf(back, BI_VALUE + " errormsg Unable to set pwd entry in auth session\n"); + fprintf(back, BI_REJECT "\n"); + return (1); + } + + expire = auth_check_change(as); + auth_close(as); + + if (expire != 0) { + fprintf(back, BI_VALUE " expire %qd\n", expire); + + if (class == NULL) + class = pwd->pw_class; + + if ((lc = login_getclass(class)) == NULL) { + dead = 0; + warn = 0; + } else { + dead = login_getcaptime(lc, "password-dead", 0, 0); + warn = login_getcaptime(lc, "password-warn", + TWOWEEKS, TWOWEEKS); + if (dead < 0) + dead = 0; + if (warn < 0) + warn = 0; + } + login_close(lc); + + /* + * If their password is dead (expired longer than + * password-dead) then just reject them. If it is + * expired but not dead yet, reject them with a + * PWEXPIRED so login knows they can still sort of + * get in. + */ + if (expire < -dead) { + fprintf(back, BI_VALUE + " errormsg Your password has expired\n"); + fprintf(back, BI_REJECT "\n"); + return (1); + } + if (expire < 0) { + if (lastchance) { + struct passwd *npwd; + + endpwent(); + + /* + * Only let them play this game once. + * Set their password change time to 1. + * This will most certainly cause any + * expired password to be dead, as well. + */ + npwd = pw_dup(pwd); + npwd->pw_change = 1; + p = pwd_update(npwd, pwd); + explicit_bzero(npwd->pw_passwd, + strlen(npwd->pw_passwd)); + free(npwd); + if (p != NULL) { + char *errval = auth_mkvalue(p); + if (errval != NULL) { + fprintf(back, BI_VALUE + " errormsg %s", errval); + free(errval); + } + fprintf(back, BI_REJECT "\n"); + return (1); + } + } + fprintf(back, BI_VALUE + " errormsg Your password has expired\n"); + fprintf(back, BI_PWEXPIRED "\n"); + return (1); + } + + /* + * If their password is not expired but is about to expire + * then warn them. + */ + if (expire <= warn) { + fprintf(back, BI_VALUE + " warnmsg Your password expires on %s\n", + ctime(&pwd->pw_change)); + } + } + return (0); +} + +static char * +pwd_update(const struct passwd *pwd, const struct passwd *opwd) +{ + int tfd, pfd; + + pw_init(); + tfd = pw_lock(0); + if (tfd < 0) { + if (errno == EEXIST) + return("the passwd file is busy."); + else + return("can't open passwd temp file"); + } + + pfd = open(_PATH_MASTERPASSWD, O_RDONLY|O_CLOEXEC, 0); + if (pfd < 0) { + pw_abort(); + return(strerror(errno)); + } + + pw_copy(pfd, tfd, pwd, opwd); + if (pw_mkdb(pwd->pw_name, 0) < 0) { + pw_abort(); + return("unable to update password database"); + } + + return(NULL); +} diff --git a/lib/liboutil/fmt_scaled.3 b/lib/liboutil/fmt_scaled.3 @@ -0,0 +1,134 @@ +.\" $OpenBSD: fmt_scaled.3,v 1.8 2016/07/16 16:10:44 jca Exp $ +.\" Copyright (c) 2001, 2003 Ian Darwin. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd $Mdocdate: July 16 2016 $ +.Dt FMT_SCALED 3 +.Os +.Sh NAME +.Nm fmt_scaled , +.Nm scan_scaled +.Nd handle numbers with a human-readable scale +.Sh SYNOPSIS +.In util.h +.Ft int +.Fn scan_scaled "char *number_w_scale" "long long *result" +.Ft int +.Fn fmt_scaled "long long number" "char *result" +.Sh DESCRIPTION +The +.Fn scan_scaled +function scans the given number and looks for a terminal scale multiplier +of B, K, M, G, T, P or E +.Pq in either upper or lower case +for Byte, Kilobyte, Megabyte, Gigabyte, Terabyte, Petabyte, Exabyte +.Po computed using powers of two, i.e., Megabyte = 1024*1024 +.Pc . +The number can have a decimal point, as in 1.5K, which returns 1536 +.Pq 1024+512 . +If no scale factor is found, B is assumed. +.Pp +The +.Fn fmt_scaled +function formats a number for display using the same +"human-readable" format, that is, a number with one of the above scale factors. +Numbers will be printed with a maximum of four digits (preceded by +a minus sign if the value is negative); values such +as 0B, 100B, 1023B, 1K, 1.5K, 5.5M, and so on, will be generated. +The +.Qq result +buffer must be allocated with at least +.Dv FMT_SCALED_STRSIZE +bytes. +The result will be left-justified in the given space, and NUL-terminated. +.Sh RETURN VALUES +The +.Fn scan_scaled +and +.Fn fmt_scaled +functions +return 0 on success. +In case of error, they return \-1, leave +.Va *result +as is, and set +.Va errno +to one of the following values: +.Dv ERANGE +if the input string represents a number that is too large to represent. +.Dv EINVAL +if an unknown character was used as scale factor, or +if the input to +.Fn scan_scaled +was malformed, e.g., too many '.' characters. +.Sh EXAMPLES +.Bd -literal -offset indent +char *cinput = "1.5K"; +long long result; +if (scan_scaled(cinput, &result) == 0) + printf("%s -> %lld\en", cinput, result); +else + fprintf(stderr, "%s - invalid\en", cinput); + +char buf[FMT_SCALED_STRSIZE]; +long long ninput = 10483892; +if (fmt_scaled(ninput, buf) == 0) + printf("%lld -> %s\en", ninput, buf); +else + fprintf(stderr, "fmt scaled failed (errno %d)", errno); +.Ed +.Sh SEE ALSO +.Xr printf 3 , +.Xr scanf 3 +.Sh HISTORY +The functions +.Fn fmt_scaled +and +.Fn scan_scaled +first appeared in +.Ox 3.4 . +.Sh AUTHORS +.An -nosplit +.An Ken Stailey +wrote the first version of the code that became +.Fn fmt_scaled , +originally inside +.Ox +.Xr df 1 . +.An Ian Darwin +excerpted this and made it into a library routine +(with significant help from +.An Paul Janzen ) , +and wrote +.Fn scan_scaled . +.Sh BUGS +Some of the scale factors have misleading meanings in lower case +(p for P is incorrect; p should be pico- and P for Peta-). +However, we bend the SI rules in favor of common sense here. +A person creating a disk partition of "100m" is unlikely to require +100 millibytes (i.e., 0.1 byte) of storage in the partition; +100 megabytes is the only reasonable interpretation. +.Pp +Cannot represent the larger scale factors on all architectures. +.Pp +Ignores the current locale. diff --git a/lib/liboutil/fmt_scaled.c b/lib/liboutil/fmt_scaled.c @@ -0,0 +1,271 @@ +/* $OpenBSD: fmt_scaled.c,v 1.12 2013/11/29 19:00:51 deraadt Exp $ */ + +/* + * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * fmt_scaled: Format numbers scaled for human comprehension + * scan_scaled: Scan numbers in this format. + * + * "Human-readable" output uses 4 digits max, and puts a unit suffix at + * the end. Makes output compact and easy-to-read esp. on huge disks. + * Formatting code was originally in OpenBSD "df", converted to library routine. + * Scanning code written for OpenBSD libutil. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +#include "util.h" + +typedef enum { + NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 +} unit_type; + +/* These three arrays MUST be in sync! XXX make a struct */ +static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; +static char scale_chars[] = "BKMGTPE"; +static long long scale_factors[] = { + 1LL, + 1024LL, + 1024LL*1024, + 1024LL*1024*1024, + 1024LL*1024*1024*1024, + 1024LL*1024*1024*1024*1024, + 1024LL*1024*1024*1024*1024*1024, +}; +#define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) + +#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ + +/* Convert the given input string "scaled" into numeric in "result". + * Return 0 on success, -1 and errno set on error. + */ +int +scan_scaled(char *scaled, long long *result) +{ + char *p = scaled; + int sign = 0; + unsigned int i, ndigits = 0, fract_digits = 0; + long long scale_fact = 1, whole = 0, fpart = 0; + + /* Skip leading whitespace */ + while (isascii((unsigned char)*p) && isspace((unsigned char)*p)) + ++p; + + /* Then at most one leading + or - */ + while (*p == '-' || *p == '+') { + if (*p == '-') { + if (sign) { + errno = EINVAL; + return -1; + } + sign = -1; + ++p; + } else if (*p == '+') { + if (sign) { + errno = EINVAL; + return -1; + } + sign = +1; + ++p; + } + } + + /* Main loop: Scan digits, find decimal point, if present. + * We don't allow exponentials, so no scientific notation + * (but note that E for Exa might look like e to some!). + * Advance 'p' to end, to get scale factor. + */ + for (; isascii((unsigned char)*p) && + (isdigit((unsigned char)*p) || *p=='.'); ++p) { + if (*p == '.') { + if (fract_digits > 0) { /* oops, more than one '.' */ + errno = EINVAL; + return -1; + } + fract_digits = 1; + continue; + } + + i = (*p) - '0'; /* whew! finally a digit we can use */ + if (fract_digits > 0) { + if (fract_digits >= MAX_DIGITS-1) + /* ignore extra fractional digits */ + continue; + fract_digits++; /* for later scaling */ + fpart *= 10; + fpart += i; + } else { /* normal digit */ + if (++ndigits >= MAX_DIGITS) { + errno = ERANGE; + return -1; + } + whole *= 10; + whole += i; + } + } + + if (sign) { + whole *= sign; + fpart *= sign; + } + + /* If no scale factor given, we're done. fraction is discarded. */ + if (!*p) { + *result = whole; + return 0; + } + + /* Validate scale factor, and scale whole and fraction by it. */ + for (i = 0; i < SCALE_LENGTH; i++) { + + /* Are we there yet? */ + if (*p == scale_chars[i] || + *p == tolower((unsigned char)scale_chars[i])) { + + /* If it ends with alphanumerics after the scale char, bad. */ + if (isalnum((unsigned char)*(p+1))) { + errno = EINVAL; + return -1; + } + scale_fact = scale_factors[i]; + + /* scale whole part */ + whole *= scale_fact; + + /* truncate fpart so it does't overflow. + * then scale fractional part. + */ + while (fpart >= LLONG_MAX / scale_fact) { + fpart /= 10; + fract_digits--; + } + fpart *= scale_fact; + if (fract_digits > 0) { + for (i = 0; i < fract_digits -1; i++) + fpart /= 10; + } + whole += fpart; + *result = whole; + return 0; + } + } + + /* Invalid unit or character */ + errno = EINVAL; + return -1; +} + +/* Format the given "number" into human-readable form in "result". + * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. + * Return 0 on success, -1 and errno set if error. + */ +int +fmt_scaled(long long number, char *result) +{ + long long abval, fract = 0; + unsigned int i; + unit_type unit = NONE; + + abval = llabs(number); + + /* Not every negative long long has a positive representation. + * Also check for numbers that are just too darned big to format + */ + if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { + errno = ERANGE; + return -1; + } + + /* scale whole part; get unscaled fraction */ + for (i = 0; i < SCALE_LENGTH; i++) { + if (abval/1024 < scale_factors[i]) { + unit = units[i]; + fract = (i == 0) ? 0 : abval % scale_factors[i]; + number /= scale_factors[i]; + if (i > 0) + fract /= scale_factors[i - 1]; + break; + } + } + + fract = (10 * fract + 512) / 1024; + /* if the result would be >= 10, round main number */ + if (fract == 10) { + if (number >= 0) + number++; + else + number--; + fract = 0; + } + + if (number == 0) + strlcpy(result, "0B", FMT_SCALED_STRSIZE); + else if (unit == NONE || number >= 100 || number <= -100) { + if (fract >= 5) { + if (number >= 0) + number++; + else + number--; + } + (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", + number, scale_chars[unit]); + } else + (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", + number, fract, scale_chars[unit]); + + return 0; +} + +#ifdef MAIN +/* + * This is the original version of the program in the man page. + * Copy-and-paste whatever you need from it. + */ +int +main(int argc, char **argv) +{ + char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE]; + long long ninput = 10483892, result; + + if (scan_scaled(cinput, &result) == 0) + printf("\"%s\" -> %lld\n", cinput, result); + else + perror(cinput); + + if (fmt_scaled(ninput, buf) == 0) + printf("%lld -> \"%s\"\n", ninput, buf); + else + fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno)); + + return 0; +} +#endif diff --git a/lib/liboutil/fparseln.3 b/lib/liboutil/fparseln.3 @@ -0,0 +1,144 @@ +.\" $OpenBSD: fparseln.3,v 1.10 2015/09/14 15:14:55 schwarze Exp $ +.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $ +.\" +.\" Copyright (c) 1997 Christos Zoulas. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Christos Zoulas. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd $Mdocdate: September 14 2015 $ +.Dt FPARSELN 3 +.Os +.Sh NAME +.Nm fparseln +.Nd return the next logical line from a stream +.Sh SYNOPSIS +.In stdio.h +.In util.h +.Ft "char *" +.Fo fparseln +.Fa "FILE *stream" "size_t *len" "size_t *lineno" +.Fa "const char delim[3]" "int flags" +.Fc +.Sh DESCRIPTION +The +.Fn fparseln +function +returns a pointer to the next logical line from the stream referenced by +.Fa stream . +This string is null terminated, contains no trailing newline, +and is dynamically allocated on each invocation. +It is the responsibility of the caller to free the pointer. +.Pp +By default, if a character is escaped, both it and the preceding escape +character will be present in the returned string. +Various +.Fa flags +alter this behaviour. +.Pp +The meaning of the arguments is as follows: +.Bl -tag -width "lineno" +.It Fa stream +The stream to read from. +.It Fa len +If not +.Dv NULL , +the length of the string is stored in the memory location referenced by +.Fa len . +.It Fa lineno +If not +.Dv NULL , +the value of the memory location to which +.Fa lineno +references is incremented by the number of lines actually read from the file. +.It Fa delim +Contains the escape, continuation, and comment characters. +If a character is NUL then processing for that character is disabled. +If +.Dv NULL , +all characters default to values specified below. +The contents of +.Fa delim +is as follows: +.Bl -tag -width "delim[0]" +.It Fa delim[0] +The escape character, which defaults to +.Ql \e , +is used to remove any special meaning from the next character. +.It Fa delim[1] +The continuation character, which defaults to +.Ql \e , +is used to indicate that the next line should be concatenated with the +current one if this character is the last character on the current line +and is not escaped. +.It Fa delim[2] +The comment character, which defaults to +.Ql # , +if not escaped indicates the beginning of a comment that extends until the +end of the current line. +.El +.It Fa flags +If non-zero, alter the operation of +.Fn fparseln . +The various flags, which may be OR'ed together, are: +.Bl -tag -width "FPARSELN_UNESCCOMM" +.It Dv FPARSELN_UNESCCOMM +Remove escape preceding an escaped comment. +.It Dv FPARSELN_UNESCCONT +Remove escape preceding an escaped continuation. +.It Dv FPARSELN_UNESCESC +Remove escape preceding an escaped escape. +.It Dv FPARSELN_UNESCREST +Remove escape preceding any other character. +.It Dv FPARSELN_UNESCALL +All of the above. +.El +.El +.Sh RETURN VALUES +Upon successful completion a pointer to the parsed line is returned; +otherwise, +.Dv NULL +is returned. +.Pp +Internally, the +.Fn fparseln +function uses +.Xr fgetln 3 , +so all error conditions that apply to +.Xr fgetln 3 +apply to +.Fn fparseln +as well. +In addition +.Fn fparseln +may set +.Va errno +to +.Er ENOMEM +and return +.Dv NULL +if it runs out of memory. +.Sh SEE ALSO +.Xr fgetln 3 diff --git a/lib/liboutil/fparseln.c b/lib/liboutil/fparseln.c @@ -0,0 +1,208 @@ +/* $OpenBSD: fparseln.c,v 1.7 2012/12/05 23:20:06 deraadt Exp $ */ +/* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "util.h" + +static int isescaped(const char *, const char *, int); + +/* isescaped(): + * Return true if the character in *p that belongs to a string + * that starts in *sp, is escaped by the escape character esc. + */ +static int +isescaped(const char *sp, const char *p, int esc) +{ + const char *cp; + size_t ne; + + /* No escape character */ + if (esc == '\0') + return 1; + + /* Count the number of escape characters that precede ours */ + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) + continue; + + /* Return true if odd number of escape characters */ + return (ne & 1) != 0; +} + + +/* fparseln(): + * Read a line from a file parsing continuations ending in \ + * and eliminating trailing newlines, or comments starting with + * the comment char. + */ +char * +fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], + int flags) +{ + static const char dstr[3] = { '\\', '\\', '#' }; + char *buf = NULL, *ptr, *cp, esc, con, nl, com; + size_t s, len = 0; + int cnt = 1; + + if (str == NULL) + str = dstr; + + esc = str[0]; + con = str[1]; + com = str[2]; + + /* + * XXX: it would be cool to be able to specify the newline character, + * but unfortunately, fgetln does not let us + */ + nl = '\n'; + + while (cnt) { + cnt = 0; + + if (lineno) + (*lineno)++; + + if ((ptr = fgetln(fp, &s)) == NULL) + break; + + if (s && com) { /* Check and eliminate comments */ + for (cp = ptr; cp < ptr + s; cp++) + if (*cp == com && !isescaped(ptr, cp, esc)) { + s = cp - ptr; + cnt = s == 0 && buf == NULL; + break; + } + } + + if (s && nl) { /* Check and eliminate newlines */ + cp = &ptr[s - 1]; + + if (*cp == nl) + s--; /* forget newline */ + } + + if (s && con) { /* Check and eliminate continuations */ + cp = &ptr[s - 1]; + + if (*cp == con && !isescaped(ptr, cp, esc)) { + s--; /* forget escape */ + cnt = 1; + } + } + + if (s == 0 && buf != NULL) + continue; + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && + strchr(buf, esc) != NULL) { + ptr = cp = buf; + while (cp[0] != '\0') { + int skipesc; + + while (cp[0] != '\0' && cp[0] != esc) + *ptr++ = *cp++; + if (cp[0] == '\0' || cp[1] == '\0') + break; + + skipesc = 0; + if (cp[1] == com) + skipesc += (flags & FPARSELN_UNESCCOMM); + if (cp[1] == con) + skipesc += (flags & FPARSELN_UNESCCONT); + if (cp[1] == esc) + skipesc += (flags & FPARSELN_UNESCESC); + if (cp[1] != com && cp[1] != con && cp[1] != esc) + skipesc = (flags & FPARSELN_UNESCREST); + + if (skipesc) + cp++; + else + *ptr++ = *cp++; + *ptr++ = *cp++; + } + *ptr = '\0'; + len = strlen(buf); + } + + if (size) + *size = len; + return buf; +} + +#ifdef TEST + +int main(int, char **); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *ptr; + size_t size, line; + + line = 0; + while ((ptr = fparseln(stdin, &size, &line, NULL, + FPARSELN_UNESCALL)) != NULL) + printf("line %d (%d) |%s|\n", line, size, ptr); + return 0; +} + +/* + +# This is a test +line 1 +line 2 \ +line 3 # Comment +line 4 \# Not comment \\\\ + +# And a comment \ +line 5 \\\ +line 6 + +*/ + +#endif /* TEST */ diff --git a/lib/liboutil/imsg-buffer.c b/lib/liboutil/imsg-buffer.c @@ -0,0 +1,309 @@ +/* $OpenBSD: imsg-buffer.c,v 1.8 2015/12/29 18:05:01 benno Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <limits.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "imsg.h" + +int ibuf_realloc(struct ibuf *, size_t); +void ibuf_enqueue(struct msgbuf *, struct ibuf *); +void ibuf_dequeue(struct msgbuf *, struct ibuf *); + +struct ibuf * +ibuf_open(size_t len) +{ + struct ibuf *buf; + + if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = buf->max = len; + buf->fd = -1; + + return (buf); +} + +struct ibuf * +ibuf_dynamic(size_t len, size_t max) +{ + struct ibuf *buf; + + if (max < len) + return (NULL); + + if ((buf = ibuf_open(len)) == NULL) + return (NULL); + + if (max > 0) + buf->max = max; + + return (buf); +} + +int +ibuf_realloc(struct ibuf *buf, size_t len) +{ + u_char *b; + + /* on static buffers max is eq size and so the following fails */ + if (buf->wpos + len > buf->max) { + errno = ERANGE; + return (-1); + } + + b = realloc(buf->buf, buf->wpos + len); + if (b == NULL) + return (-1); + buf->buf = b; + buf->size = buf->wpos + len; + + return (0); +} + +int +ibuf_add(struct ibuf *buf, const void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +void * +ibuf_reserve(struct ibuf *buf, size_t len) +{ + void *b; + + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); +} + +void * +ibuf_seek(struct ibuf *buf, size_t pos, size_t len) +{ + /* only allowed to seek in already written parts */ + if (pos + len > buf->wpos) + return (NULL); + + return (buf->buf + pos); +} + +size_t +ibuf_size(struct ibuf *buf) +{ + return (buf->wpos); +} + +size_t +ibuf_left(struct ibuf *buf) +{ + return (buf->max - buf->wpos); +} + +void +ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) +{ + ibuf_enqueue(msgbuf, buf); +} + +int +ibuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + + memset(&iov, 0, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + } + +again: + if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_free(struct ibuf *buf) +{ + if (buf == NULL) + return; + free(buf->buf); + free(buf); +} + +void +msgbuf_init(struct msgbuf *msgbuf) +{ + msgbuf->queued = 0; + msgbuf->fd = -1; + TAILQ_INIT(&msgbuf->bufs); +} + +void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct ibuf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + ibuf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} + +void +msgbuf_clear(struct msgbuf *msgbuf) +{ + struct ibuf *buf; + + while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) + ibuf_dequeue(msgbuf, buf); +} + +int +msgbuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + memset(&iov, 0, sizeof(iov)); + memset(&msg, 0, sizeof(msg)); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + if (buf->fd != -1) + break; + } + + msg.msg_iov = iov; + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = buf->fd; + } + +again: + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + if (errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + /* + * assumption: fd got sent if sendmsg sent anything + * this works because fds are passed one at a time + */ + if (buf != NULL && buf->fd != -1) { + close(buf->fd); + buf->fd = -1; + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); + msgbuf->queued++; +} + +void +ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_REMOVE(&msgbuf->bufs, buf, entry); + + if (buf->fd != -1) + close(buf->fd); + + msgbuf->queued--; + ibuf_free(buf); +} diff --git a/lib/liboutil/imsg.c b/lib/liboutil/imsg.c @@ -0,0 +1,302 @@ +/* $OpenBSD: imsg.c,v 1.13 2015/12/09 11:54:12 tb Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "imsg.h" + +int imsg_fd_overhead = 0; + +int imsg_get_fd(struct imsgbuf *); + +void +imsg_init(struct imsgbuf *ibuf, int fd) +{ + msgbuf_init(&ibuf->w); + memset(&ibuf->r, 0, sizeof(ibuf->r)); + ibuf->fd = fd; + ibuf->w.fd = fd; + ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); +} + +ssize_t +imsg_read(struct imsgbuf *ibuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 1)]; + } cmsgbuf; + struct iovec iov; + ssize_t n = -1; + int fd; + struct imsg_fd *ifd; + + memset(&msg, 0, sizeof(msg)); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); + + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) + return (-1); + +again: + if (getdtablecount() + imsg_fd_overhead + + (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) + >= getdtablesize()) { + errno = EAGAIN; + free(ifd); + return (-1); + } + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno == EINTR) + goto again; + goto fail; + } + + ibuf->r.wpos += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int i; + int j; + + /* + * We only accept one file descriptor. Due to C + * padding rules, our control buffer might contain + * more than one fd, and we must close them. + */ + j = ((char *)cmsg + cmsg->cmsg_len - + (char *)CMSG_DATA(cmsg)) / sizeof(int); + for (i = 0; i < j; i++) { + fd = ((int *)CMSG_DATA(cmsg))[i]; + if (ifd != NULL) { + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, + entry); + ifd = NULL; + } else + close(fd); + } + } + /* we do not handle other ctl data level */ + } + +fail: + free(ifd); + return (n); +} + +ssize_t +imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +{ + size_t av, left, datalen; + + av = ibuf->r.wpos; + + if (IMSG_HEADER_SIZE > av) + return (0); + + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { + errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; + if (datalen == 0) + imsg->data = NULL; + else if ((imsg->data = malloc(datalen)) == NULL) + return (-1); + + if (imsg->hdr.flags & IMSGF_HASFD) + imsg->fd = imsg_get_fd(ibuf); + else + imsg->fd = -1; + + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { + left = av - imsg->hdr.len; + memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); + ibuf->r.wpos = left; + } else + ibuf->r.wpos = 0; + + return (datalen + IMSG_HEADER_SIZE); +} + +int +imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, const void *data, u_int16_t datalen) +{ + struct ibuf *wbuf; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + if (imsg_add(wbuf, data, datalen) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +int +imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + struct ibuf *wbuf; + int i, datalen = 0; + + for (i = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) + if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +/* ARGSUSED */ +struct ibuf * +imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, u_int16_t datalen) +{ + struct ibuf *wbuf; + struct imsg_hdr hdr; + + datalen += IMSG_HEADER_SIZE; + if (datalen > MAX_IMSGSIZE) { + errno = ERANGE; + return (NULL); + } + + hdr.type = type; + hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; + if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + return (NULL); + + return (wbuf); +} + +int +imsg_add(struct ibuf *msg, const void *data, u_int16_t datalen) +{ + if (datalen) + if (ibuf_add(msg, data, datalen) == -1) { + ibuf_free(msg); + return (-1); + } + return (datalen); +} + +void +imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) +{ + struct imsg_hdr *hdr; + + hdr = (struct imsg_hdr *)msg->buf; + + hdr->flags &= ~IMSGF_HASFD; + if (msg->fd != -1) + hdr->flags |= IMSGF_HASFD; + + hdr->len = (u_int16_t)msg->wpos; + + ibuf_close(&ibuf->w, msg); +} + +void +imsg_free(struct imsg *imsg) +{ + free(imsg->data); +} + +int +imsg_get_fd(struct imsgbuf *ibuf) +{ + int fd; + struct imsg_fd *ifd; + + if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + return (-1); + + fd = ifd->fd; + TAILQ_REMOVE(&ibuf->fds, ifd, entry); + free(ifd); + + return (fd); +} + +int +imsg_flush(struct imsgbuf *ibuf) +{ + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) <= 0) + return (-1); + return (0); +} + +void +imsg_clear(struct imsgbuf *ibuf) +{ + int fd; + + msgbuf_clear(&ibuf->w); + while ((fd = imsg_get_fd(ibuf)) != -1) + close(fd); +} diff --git a/lib/liboutil/imsg.h b/lib/liboutil/imsg.h @@ -0,0 +1,112 @@ +/* $OpenBSD: imsg.h,v 1.3 2013/12/26 17:32:33 eric Exp $ */ + +/* + * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> + * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IMSG_H_ +#define _IMSG_H_ + +#define IBUF_READ_SIZE 65535 +#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +#define MAX_IMSGSIZE 16384 + +struct ibuf { + TAILQ_ENTRY(ibuf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + u_int32_t queued; + int fd; +}; + +struct ibuf_read { + u_char buf[IBUF_READ_SIZE]; + u_char *rptr; + size_t wpos; +}; + +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct ibuf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; + +#define IMSGF_HASFD 1 + +struct imsg_hdr { + u_int32_t type; + u_int16_t len; + u_int16_t flags; + u_int32_t peerid; + u_int32_t pid; +}; + +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + + +/* buffer.c */ +struct ibuf *ibuf_open(size_t); +struct ibuf *ibuf_dynamic(size_t, size_t); +int ibuf_add(struct ibuf *, const void *, size_t); +void *ibuf_reserve(struct ibuf *, size_t); +void *ibuf_seek(struct ibuf *, size_t, size_t); +size_t ibuf_size(struct ibuf *); +size_t ibuf_left(struct ibuf *); +void ibuf_close(struct msgbuf *, struct ibuf *); +int ibuf_write(struct msgbuf *); +void ibuf_free(struct ibuf *); +void msgbuf_init(struct msgbuf *); +void msgbuf_clear(struct msgbuf *); +int msgbuf_write(struct msgbuf *); +void msgbuf_drain(struct msgbuf *, size_t); + +/* imsg.c */ +void imsg_init(struct imsgbuf *, int); +ssize_t imsg_read(struct imsgbuf *); +ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, const void *, u_int16_t); +int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, const struct iovec *, int); +struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + u_int16_t); +int imsg_add(struct ibuf *, const void *, u_int16_t); +void imsg_close(struct imsgbuf *, struct ibuf *); +void imsg_free(struct imsg *); +int imsg_flush(struct imsgbuf *); +void imsg_clear(struct imsgbuf *); + +#endif diff --git a/lib/liboutil/imsg_init.3 b/lib/liboutil/imsg_init.3 @@ -0,0 +1,550 @@ +.\" $OpenBSD: imsg_init.3,v 1.15 2015/12/29 18:05:23 benno Exp $ +.\" +.\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER +.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING +.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 29 2015 $ +.Dt IMSG_INIT 3 +.Os +.Sh NAME +.Nm imsg_init , +.Nm imsg_read , +.Nm imsg_get , +.Nm imsg_compose , +.Nm imsg_composev , +.Nm imsg_create , +.Nm imsg_add , +.Nm imsg_close , +.Nm imsg_free , +.Nm imsg_flush , +.Nm imsg_clear , +.Nm ibuf_open , +.Nm ibuf_dynamic , +.Nm ibuf_add , +.Nm ibuf_reserve , +.Nm ibuf_seek , +.Nm ibuf_size , +.Nm ibuf_left , +.Nm ibuf_close , +.Nm ibuf_write , +.Nm ibuf_free , +.Nm msgbuf_init , +.Nm msgbuf_clear , +.Nm msgbuf_write , +.Nm msgbuf_drain +.Nd IPC messaging functions +.Sh SYNOPSIS +.In sys/types.h +.In sys/queue.h +.In sys/uio.h +.In imsg.h +.Ft void +.Fn imsg_init "struct imsgbuf *ibuf" "int fd" +.Ft ssize_t +.Fn imsg_read "struct imsgbuf *ibuf" +.Ft ssize_t +.Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg" +.Ft int +.Fn imsg_compose "struct imsgbuf *ibuf" "u_int32_t type" "uint32_t peerid" \ + "pid_t pid" "int fd" "const void *data" "u_int16_t datalen" +.Ft int +.Fn imsg_composev "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \ + "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt" +.Ft "struct ibuf *" +.Fn imsg_create "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \ + "pid_t pid" "u_int16_t datalen" +.Ft int +.Fn imsg_add "struct ibuf *buf" "const void *data" "u_int16_t datalen" +.Ft void +.Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg" +.Ft void +.Fn imsg_free "struct imsg *imsg" +.Ft int +.Fn imsg_flush "struct imsgbuf *ibuf" +.Ft void +.Fn imsg_clear "struct imsgbuf *ibuf" +.Ft "struct ibuf *" +.Fn ibuf_open "size_t len" +.Ft "struct ibuf *" +.Fn ibuf_dynamic "size_t len" "size_t max" +.Ft int +.Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len" +.Ft "void *" +.Fn ibuf_reserve "struct ibuf *buf" "size_t len" +.Ft "void *" +.Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len" +.Ft size_t +.Fn ibuf_size "struct ibuf *buf" +.Ft size_t +.Fn ibuf_left "struct ibuf *buf" +.Ft void +.Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf" +.Ft int +.Fn ibuf_write "struct msgbuf *msgbuf" +.Ft void +.Fn ibuf_free "struct ibuf *buf" +.Ft void +.Fn msgbuf_init "struct msgbuf *msgbuf" +.Ft void +.Fn msgbuf_clear "struct msgbuf *msgbuf" +.Ft int +.Fn msgbuf_write "struct msgbuf *msgbuf" +.Ft void +.Fn msgbuf_drain "struct msgbuf *msgbuf" "size_t n" +.Sh DESCRIPTION +The +.Nm imsg +functions provide a simple mechanism for communication between processes +using sockets. +Each transmitted message is guaranteed to be presented to the receiving program +whole. +They are commonly used in privilege separated processes, where processes with +different rights are required to cooperate. +.Pp +A program using these functions should be linked with +.Em -lutil . +.Pp +The basic +.Nm +structure is the +.Em imsgbuf , +which wraps a file descriptor and represents one side of a channel on which +messages are sent and received: +.Bd -literal -offset indent +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct ibuf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; +.Ed +.Pp +.Fn imsg_init +is a routine which initializes +.Fa ibuf +as one side of a channel associated with +.Fa fd . +The file descriptor is used to send and receive messages, +but is not closed by any of the imsg functions. +An imsgbuf is initialized with the +.Em w +member as the output buffer queue, +.Em fd +with the file descriptor passed to +.Fn imsg_init +and the other members for internal use only. +.Pp +The +.Fn imsg_clear +function frees any data allocated as part of an imsgbuf. +.Pp +.Fn imsg_create , +.Fn imsg_add +and +.Fn imsg_close +are generic construction routines for messages that are to be sent using an +imsgbuf. +.Pp +.Fn imsg_create +creates a new message with header specified by +.Fa type , +.Fa peerid +and +.Fa pid . +A +.Fa pid +of zero uses the process ID returned by +.Xr getpid 2 +when +.Fa ibuf +was initialized. +In addition to this common imsg header, +.Fa datalen +bytes of space may be reserved for attaching to this imsg. +This space is populated using +.Fn imsg_add . +Additionally, the file descriptor +.Fa fd +may be passed over the socket to the other process. +If +.Fa fd +is given, it is closed in the sending program after the message is sent. +A value of \-1 indicates no file descriptor should be passed. +.Fn imsg_create +returns a pointer to a new message if it succeeds, NULL otherwise. +.Pp +.Fn imsg_add +appends to +.Fa imsg +.Fa len +bytes of ancillary data pointed to by +.Fa buf . +It returns +.Fa len +if it succeeds, \-1 otherwise. +.Pp +.Fn imsg_close +completes creation of +.Fa imsg +by adding it to +.Fa imsgbuf +output buffer. +.Pp +.Fn imsg_compose +is a routine which is used to quickly create and queue an imsg. +It takes the same parameters as the +.Fn imsg_create , +.Fn imsg_add +and +.Fn imsg_close +routines, +except that only one ancillary data buffer can be provided. +This routine returns 1 if it succeeds, \-1 otherwise. +.Pp +.Fn imsg_composev +is similar to +.Fn imsg_compose . +It takes the same parameters, except that the ancillary data buffer is specified +by +.Fa iovec . +.Pp +.Fn imsg_flush +is a function which calls +.Fn msgbuf_write +in a loop until all imsgs in the output buffer are sent. +It returns 0 if it succeeds, \-1 otherwise. +.Pp +The +.Fn imsg_read +routine reads pending data with +.Xr recvmsg 2 +and queues it as individual messages on +.Fa imsgbuf . +It returns the number of bytes read on success, or \-1 on error. +A return value of \-1 from +.Fn imsg_read +invalidates +.Fa imsgbuf , +and renders it suitable only for passing to +.Fn imsg_clear . +.Pp +.Fn imsg_get +fills in an individual imsg pending on +.Fa imsgbuf +into the structure pointed to by +.Fa imsg . +It returns the total size of the message, 0 if no messages are ready, or \-1 +for an error. +Received messages are returned as a +.Em struct imsg , +which must be freed by +.Fn imsg_free +when no longer required. +.Em struct imsg +has this form: +.Bd -literal -offset indent +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + +struct imsg_hdr { + u_int32_t type; + u_int16_t len; + u_int16_t flags; + u_int32_t peerid; + u_int32_t pid; +}; +.Ed +.Pp +The header members are: +.Bl -tag -width Ds -offset indent +.It type +A integer identifier, typically used to express the meaning of the message. +.It len +The total length of the imsg, including the header and any ancillary data +transmitted with the message (pointed to by the +.Em data +member of the message itself). +.It flags +Flags used internally by the imsg functions: should not be used by application +programs. +.It peerid, pid +32-bit values specified on message creation and free for any use by the +caller, normally used to identify the message sender. +.El +.Pp +In addition, +.Em struct imsg +has the following: +.Bl -tag -width Ds -offset indent +.It fd +The file descriptor specified when the message was created and passed using the +socket control message API, or \-1 if no file descriptor was sent. +.It data +A pointer to the ancillary data transmitted with the imsg. +.El +.Pp +The IMSG_HEADER_SIZE define is the size of the imsg message header, which +may be subtracted from the +.Fa len +member of +.Em struct imsg_hdr +to obtain the length of any additional data passed with the message. +.Pp +MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently +16384 bytes. +.Sh BUFFERS +The imsg API defines functions to manipulate buffers, used internally and during +construction of imsgs with +.Fn imsg_create . +A +.Em struct ibuf +is a single buffer and a +.Em struct msgbuf +a queue of output buffers for transmission: +.Bd -literal -offset indent +struct ibuf { + TAILQ_ENTRY(ibuf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + u_int32_t queued; + int fd; +}; +.Ed +.Pp +The +.Fn ibuf_open +function allocates a fixed-length buffer. +The buffer may not be resized and may contain a maximum of +.Fa len +bytes. +On success +.Fn ibuf_open +returns a pointer to the buffer; on failure it returns NULL. +.Pp +.Fn ibuf_dynamic +allocates a resizeable buffer of initial length +.Fa len +and maximum size +.Fa max . +Buffers allocated with +.Fn ibuf_dynamic +are automatically grown if necessary when data is added. +.Pp +.Fn ibuf_add +is a routine which appends a block of data to +.Fa buf . +0 is returned on success and \-1 on failure. +.Pp +.Fn ibuf_reserve +is used to reserve +.Fa len +bytes in +.Fa buf . +A pointer to the start of the reserved space is returned, or NULL on error. +.Pp +.Fn ibuf_seek +is a function which returns a pointer to the part of the buffer at offset +.Fa pos +and of extent +.Fa len . +NULL is returned if the requested range is outside the part of the buffer +in use. +.Pp +.Fn ibuf_size +and +.Fn ibuf_left +are functions which return the total bytes used and available in +.Fa buf +respectively. +.Pp +.Fn ibuf_close +appends +.Fa buf +to +.Fa msgbuf +ready to be sent. +.Pp +The +.Fn ibuf_write +routine transmits as many pending buffers as possible from +.Fn msgbuf +using +.Xr writev 2 . +It returns 1 if it succeeds, \-1 on error and 0 when no buffers were +pending or an EOF condition on the socket is detected. +Temporary resource shortages are returned with errno +.Er EAGAIN +and require the application to retry again in the future. +.Pp +.Fn ibuf_free +frees +.Fa buf +and any associated storage. +If +.Fa buf +is a NULL pointer, no action occurs. +.Pp +The +.Fn msgbuf_init +function initializes +.Fa msgbuf +so that buffers may be appended to it. +The +.Em fd +member should also be set directly before +.Fn msgbuf_write +is used. +.Pp +.Fn msgbuf_clear +empties a msgbuf, removing and discarding any queued buffers. +.Pp +The +.Fn msgbuf_write +routine calls +.Xr sendmsg 2 +to transmit buffers queued in +.Fa msgbuf . +It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty +or an EOF condition on the socket is detected. +Temporary resource shortages are returned with errno +.Er EAGAIN +and require the application to retry again in the future. +.Pp +.Fn msgbuf_drain +discards data from buffers queued in +.Fa msgbuf +until +.Fa n +bytes have been removed or +.Fa msgbuf +is empty. +.Sh EXAMPLES +In a typical program, a channel between two processes is created with +.Xr socketpair 2 , +and an +.Em imsgbuf +created around one file descriptor in each process: +.Bd -literal -offset indent +struct imsgbuf parent_ibuf, child_ibuf; +int imsg_fds[2]; + +if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) + err(1, "socketpair"); + +switch (fork()) { +case -1: + err(1, "fork"); +case 0: + /* child */ + close(imsg_fds[0]); + imsg_init(&child_ibuf, imsg_fds[1]); + exit(child_main(&child_ibuf)); +} + +/* parent */ +close(imsg_fds[1]); +imsg_init(&parent_ibuf, imsg_fds[0]); +exit(parent_main(&parent_ibuf)); +.Ed +.Pp +Messages may then be composed and queued on the +.Em imsgbuf , +for example using the +.Fn imsg_compose +function: +.Bd -literal -offset indent +enum imsg_type { + IMSG_A_MESSAGE, + IMSG_MESSAGE2 +}; + +int +child_main(struct imsgbuf *ibuf) +{ + int idata; + ... + idata = 42; + imsg_compose(ibuf, IMSG_A_MESSAGE, + 0, 0, -1, &idata, sizeof idata); + ... +} +.Ed +.Pp +A mechanism such as +.Xr poll 2 +or the +.Xr event 3 +library is used to monitor the socket file descriptor. +When the socket is ready for writing, queued messages are transmitted with +.Fn msgbuf_write : +.Bd -literal -offset indent + if (msgbuf_write(&ibuf-\*(Gtw) \*(Lt= 0 && errno != EAGAIN) { + /* handle write failure */ + } +.Ed +.Pp +And when ready for reading, messages are first received using +.Fn imsg_read +and then extracted with +.Fn imsg_get : +.Bd -literal -offset indent +void +dispatch_imsg(struct imsgbuf *ibuf) +{ + struct imsg imsg; + ssize_t n, datalen; + int idata; + + if (((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) || n == 0) { + /* handle socket error */ + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) { + /* handle read error */ + } + if (n == 0) /* no more messages */ + return; + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case IMSG_A_MESSAGE: + if (datalen \*(Lt sizeof idata) { + /* handle corrupt message */ + } + memcpy(&idata, imsg.data, sizeof idata); + /* handle message received */ + break; + ... + } + + imsg_free(&imsg); + } +} +.Ed +.Sh SEE ALSO +.Xr socketpair 2 , +.Xr unix 4 diff --git a/lib/liboutil/isduid.3 b/lib/liboutil/isduid.3 @@ -0,0 +1,61 @@ +.\" $OpenBSD: isduid.3,v 1.3 2015/07/15 15:16:59 sobrado Exp $ +.\" +.\" * Copyright (c) Joel Sing <jsing@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 15 2015 $ +.Dt ISDUID 3 +.Os +.Sh NAME +.Nm isduid +.Nd disklabel UID test +.Sh SYNOPSIS +.In util.h +.Ft int +.Fn isduid "char *duid" "int dflags" +.Sh DESCRIPTION +The +.Fn isduid +function tests the string +.Fa duid +to see if it is a valid +.Xr disklabel 8 +UID. +The +.Fa dflags +are specified using the same flags as used by +.Xr opendev 3 . +.Pp +If the OPENDEV_PART flag is included in +.Fa dflags +the disklabel UID must consist of a 16-character hexadecimal string. +Otherwise the disklabel UID must consist of a 16-character hexadecimal string +followed by a +.Sq \&. +and a partition letter. +.Sh RETURN VALUES +The +.Fn isduid +function returns non-zero if +.Fa duid +is a valid DUID, otherwise zero is returned. +.Sh SEE ALSO +.Xr opendev 3 , +.Xr disklabel 5 , +.Xr disklabel 8 +.Sh HISTORY +The +.Fn isduid +function first appeared in +.Ox 4.9 . diff --git a/lib/liboutil/logwtmp.c b/lib/liboutil/logwtmp.c @@ -0,0 +1,65 @@ +/* $OpenBSD: logwtmp.c,v 1.9 2005/08/02 21:46:23 espie Exp $ */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <utmp.h> + +#include "util.h" + +void +logwtmp(const char *line, const char *name, const char *host) +{ + struct stat buf; + struct utmp ut; + int fd; + + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (fstat(fd, &buf) == 0) { + (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void) strncpy(ut.ut_name, name, sizeof(ut.ut_name)); + (void) strncpy(ut.ut_host, host, sizeof(ut.ut_host)); +#ifdef __linux + (void) time((time_t *)&ut.ut_tv.tv_sec); +#else + (void) time(&ut.ut_time); +#endif + if (write(fd, &ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void) ftruncate(fd, buf.st_size); + } + (void) close(fd); +} diff --git a/lib/liboutil/ohash.c b/lib/liboutil/ohash.c @@ -0,0 +1,327 @@ +/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ + +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include "ohash.h" + +struct _ohash_record { + uint32_t hv; + const char *p; +}; + +#define DELETED ((const char *)h) +#define NONE (h->size) + +/* Don't bother changing the hash table if the change is small enough. */ +#define MINSIZE (1UL << 4) +#define MINDELETED 4 + +static void ohash_resize(struct ohash *); + + +/* This handles the common case of variable length keys, where the + * key is stored at the end of the record. + */ +void * +ohash_create_entry(struct ohash_info *i, const char *start, const char **end) +{ + char *p; + + if (!*end) + *end = start + strlen(start); + p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); + if (p) { + memcpy(p+i->key_offset, start, *end-start); + p[i->key_offset + (*end - start)] = '\0'; + } + return (void *)p; +} + +/* hash_delete only frees the hash structure. Use hash_first/hash_next + * to free entries as well. */ +void +ohash_delete(struct ohash *h) +{ + (h->info.free)(h->t, h->info.data); +#ifndef NDEBUG + h->t = NULL; +#endif +} + +static void +ohash_resize(struct ohash *h) +{ + struct _ohash_record *n; + size_t ns; + unsigned int j; + unsigned int i, incr; + + if (4 * h->deleted < h->total) { + if (h->size >= (UINT_MAX >> 1U)) + ns = UINT_MAX; + else + ns = h->size << 1U; + } else if (3 * h->deleted > 2 * h->total) + ns = h->size >> 1U; + else + ns = h->size; + if (ns < MINSIZE) + ns = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_EXPAND++; + STAT_HASH_SIZE += ns - h->size; +#endif + + n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); + if (!n) + return; + + for (j = 0; j < h->size; j++) { + if (h->t[j].p != NULL && h->t[j].p != DELETED) { + i = h->t[j].hv % ns; + incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; + while (n[i].p != NULL) { + i += incr; + if (i >= ns) + i -= ns; + } + n[i].hv = h->t[j].hv; + n[i].p = h->t[j].p; + } + } + (h->info.free)(h->t, h->info.data); + h->t = n; + h->size = ns; + h->total -= h->deleted; + h->deleted = 0; +} + +void * +ohash_remove(struct ohash *h, unsigned int i) +{ + void *result = (void *)h->t[i].p; + + if (result == NULL || result == DELETED) + return NULL; + +#ifdef STATS_HASH + STAT_HASH_ENTRIES--; +#endif + h->t[i].p = DELETED; + h->deleted++; + if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) + ohash_resize(h); + return result; +} + +void * +ohash_find(struct ohash *h, unsigned int i) +{ + if (h->t[i].p == DELETED) + return NULL; + else + return (void *)h->t[i].p; +} + +void * +ohash_insert(struct ohash *h, unsigned int i, void *p) +{ +#ifdef STATS_HASH + STAT_HASH_ENTRIES++; +#endif + if (h->t[i].p == DELETED) { + h->deleted--; + h->t[i].p = p; + } else { + h->t[i].p = p; + /* Arbitrary resize boundary. Tweak if not efficient enough. */ + if (++h->total * 4 > h->size * 3) + ohash_resize(h); + } + return p; +} + +unsigned int +ohash_entries(struct ohash *h) +{ + return h->total - h->deleted; +} + +void * +ohash_first(struct ohash *h, unsigned int *pos) +{ + *pos = 0; + return ohash_next(h, pos); +} + +void * +ohash_next(struct ohash *h, unsigned int *pos) +{ + for (; *pos < h->size; (*pos)++) + if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) + return (void *)h->t[(*pos)++].p; + return NULL; +} + +void +ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) +{ + h->size = 1UL << size; + if (h->size < MINSIZE) + h->size = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_CREATION++; + STAT_HASH_SIZE += h->size; +#endif + /* Copy info so that caller may free it. */ + h->info.key_offset = info->key_offset; + h->info.calloc = info->calloc; + h->info.free = info->free; + h->info.alloc = info->alloc; + h->info.data = info->data; + h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), + h->info.data); + h->total = h->deleted = 0; +} + +uint32_t +ohash_interval(const char *s, const char **e) +{ + uint32_t k; + + if (!*e) + *e = s + strlen(s); + if (s == *e) + k = 0; + else + k = *s++; + while (s != *e) + k = ((k << 2) | (k >> 30)) ^ *s++; + return k; +} + +unsigned int +ohash_lookup_interval(struct ohash *h, const char *start, const char *end, + uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + strncmp(h->t[i].p+h->info.key_offset, start, + end - start) == 0 && + (h->t[i].p+h->info.key_offset)[end-start] == '\0') { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + return i; + } + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + } return i; + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_qlookup(struct ohash *h, const char *s) +{ + const char *e = NULL; + return ohash_qlookupi(h, s, &e); +} + +unsigned int +ohash_qlookupi(struct ohash *h, const char *s, const char **e) +{ + uint32_t hv; + + hv = ohash_interval(s, e); + return ohash_lookup_interval(h, s, *e, hv); +} diff --git a/lib/liboutil/ohash.h b/lib/liboutil/ohash.h @@ -0,0 +1,74 @@ +/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ + +/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef OHASH_H +#define OHASH_H + +/* Open hashing support. + * Open hashing was chosen because it is much lighter than other hash + * techniques, and more efficient in most cases. + */ + +/* user-visible data structure */ +struct ohash_info { + ptrdiff_t key_offset; + void *data; /* user data */ + void *(*calloc)(size_t, size_t, void *); + void (*free)(void *, void *); + void *(*alloc)(size_t, void *); +}; + +struct _ohash_record; + +/* private structure. It's there just so you can do a sizeof */ +struct ohash { + struct _ohash_record *t; + struct ohash_info info; + unsigned int size; + unsigned int total; + unsigned int deleted; +}; + +/* For this to be tweakable, we use small primitives, and leave part of the + * logic to the client application. e.g., hashing is left to the client + * application. We also provide a simple table entry lookup that yields + * a hashing table index (opaque) to be used in find/insert/remove. + * The keys are stored at a known position in the client data. + */ +__BEGIN_DECLS +void ohash_init(struct ohash *, unsigned, struct ohash_info *); +void ohash_delete(struct ohash *); + +unsigned int ohash_lookup_interval(struct ohash *, const char *, + const char *, uint32_t); +unsigned int ohash_lookup_memory(struct ohash *, const char *, + size_t, uint32_t) + __attribute__ ((__bounded__(__string__,2,3))); +void *ohash_find(struct ohash *, unsigned int); +void *ohash_remove(struct ohash *, unsigned int); +void *ohash_insert(struct ohash *, unsigned int, void *); +void *ohash_first(struct ohash *, unsigned int *); +void *ohash_next(struct ohash *, unsigned int *); +unsigned int ohash_entries(struct ohash *); + +void *ohash_create_entry(struct ohash_info *, const char *, const char **); +uint32_t ohash_interval(const char *, const char **); + +unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); +unsigned int ohash_qlookup(struct ohash *, const char *); +__END_DECLS +#endif diff --git a/lib/liboutil/ohash_init.3 b/lib/liboutil/ohash_init.3 @@ -0,0 +1,271 @@ +.\" $OpenBSD: ohash_init.3,v 1.2 2014/05/13 14:01:41 jmc Exp $ +.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 13 2014 $ +.Dt OHASH_INIT 3 +.Os +.Sh NAME +.Nm ohash_init , +.Nm ohash_delete , +.Nm ohash_lookup_interval , +.Nm ohash_lookup_memory , +.Nm ohash_find , +.Nm ohash_remove , +.Nm ohash_insert , +.Nm ohash_first , +.Nm ohash_next , +.Nm ohash_entries +.Nd light-weight open hashing +.Sh SYNOPSIS +.In stdint.h +.In stddef.h +.In ohash.h +.Ft void +.Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info" +.Ft void +.Fn ohash_delete "struct ohash *h" +.Ft "unsigned int" +.Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv" +.Ft "unsigned int" +.Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv" +.Ft void * +.Fn ohash_find "struct ohash *h" "unsigned int i" +.Ft void * +.Fn ohash_remove "struct ohash *h" "unsigned int i" +.Ft void * +.Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p" +.Ft void * +.Fn ohash_first "struct ohash *h" "unsigned int *i" +.Ft void * +.Fn ohash_next "struct ohash *h" "unsigned int *i" +.Ft "unsigned int" +.Fn ohash_entries "struct ohash *h" +.Sh DESCRIPTION +These functions have been designed as a fast, extensible alternative to +the usual hash table functions. +They provide storage and retrieval of records indexed by keys, +where a key is a contiguous sequence of bytes at a fixed position in +each record. +Keys can either be NUL-terminated strings or fixed-size memory areas. +All functions take a pointer to an ohash structure as the +.Fa h +function argument. +Storage for this structure should be provided by user code. +.Pp +.Fn ohash_init +initializes the table to store roughly 2 to the power +.Fa size +elements. +.Fa info +is a pointer to a +.Fa struct ohash_info . +.Bd -literal -offset indent +struct ohash_info { + ptrdiff_t key_offset; + void *data; /* user data */ + void *(*calloc)(size_t, size_t, void *); + void (*free)(void *, void *); + void *(*alloc)(size_t, void *); +}; +.Ed +.Pp +The +.Va offset +field holds the position of the key in each record; +the +.Va calloc +and +.Va free +fields are pointers to +.Xr calloc 3 +and +.Xr free 3 Ns -like +functions, used for managing the table internal storage; +the +.Va alloc +field is only used by the utility function +.Xr ohash_create_entry 3 . +.Pp +Each of these functions are called similarly to their standard counterpart, +but with an extra +.Ft void * +parameter corresponding to the content of the field +.Fa data , +which can be used to communicate specific information to the functions. +.Pp +.Fn ohash_init +stores a copy of those fields internally, so +.Fa info +can be reclaimed after initialization. +.Pp +.Fn ohash_delete +frees storage internal to +.Fa h . +Elements themselves should be freed by the user first, using for instance +.Fn ohash_first +and +.Fn ohash_next . +.Pp +.Fn ohash_lookup_interval +and +.Fn ohash_lookup_memory +are the basic look-up element functions. +The hashing function result is provided by the user as +.Fa hv . +These return a +.Qq slot +in the ohash table +.Fa h , +to be used with +.Fn ohash_find , +.Fn ohash_insert , +or +.Fn ohash_remove . +This slot is only valid up to the next call to +.Fn ohash_insert +or +.Fn ohash_remove . +.Pp +.Fn ohash_lookup_interval +handles string-like keys. +.Fn ohash_lookup_interval +assumes the key is the interval between +.Fa start +and +.Fa end , +exclusive, +though the actual elements stored in the table should only contain +NUL-terminated keys. +.Pp +.Fn ohash_lookup_memory +assumes the key is the memory area starting at +.Fa k +of size +.Fa s . +All bytes are significant in key comparison. +.Pp +.Fn ohash_find +retrieves an element from a slot +.Fa i +returned by the +.Fn ohash_lookup* +functions. +It returns +.Dv NULL +if the slot is empty. +.Pp +.Fn ohash_insert +inserts a new element +.Fa p +at slot +.Fa i . +Slot +.Fa i +must be empty and element +.Fa p +must have a key corresponding to the +.Fn ohash_lookup* +call. +.Pp +.Fn ohash_remove +removes the element at slot +.Fa i . +It returns the removed element, for user code to dispose of, or +.Dv NULL +if the slot was empty. +.Pp +.Fn ohash_first +and +.Fn ohash_next +can be used to access all elements in an ohash table, like this: +.Bd -literal -offset indent +for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i)) + do_something_with(n); +.Ed +.Pp +.Fa i +points to an auxiliary unsigned integer used to record the current position +in the ohash table. +Those functions are safe to use even while entries are added to/removed +from the table, but in such a case they don't guarantee that new entries +will be returned. +As a special case, they can safely be used to free elements in the table. +.Pp +.Fn ohash_entries +returns the number of elements in the hash table. +.Sh STORAGE HANDLING +Only +.Fn ohash_init , +.Fn ohash_insert , +.Fn ohash_remove +and +.Fn ohash_delete +may call the user-supplied memory functions: +.Bd -literal -offset indent +p = (*info->calloc)(n, sizeof_record, info->data); +/* copy data from old to p */ +(*info->free)(old, info->data); +.Ed +.Pp +It is the responsibility of the user memory allocation code to verify +that those calls did not fail. +.Pp +If memory allocation fails, +.Fn ohash_init +returns a useless hash table. +.Fn ohash_insert +and +.Fn ohash_remove +still perform the requested operation, but the returned table should be +considered read-only. +It can still be accessed by +.Fn ohash_lookup* , +.Fn ohash_find , +.Fn ohash_first +and +.Fn ohash_next +to dump relevant information to disk before aborting. +.Sh THREAD SAFETY +The open hashing functions are not thread-safe by design. +In particular, in a threaded environment, there is no guarantee that a +.Qq slot +will not move between a +.Fn ohash_lookup* +and a +.Fn ohash_find , +.Fn ohash_insert +or +.Fn ohash_remove +call. +.Pp +Multi-threaded applications should explicitly protect ohash table access. +.Sh SEE ALSO +.Xr hcreate 3 , +.Xr ohash_interval 3 +.Rs +.%A Donald E. Knuth +.%B The Art of Computer Programming +.%V Vol. 3 +.%P pp 506-550 +.%D 1973 +.Re +.Sh STANDARDS +Those functions are completely non-standard and should be avoided in +portable programs. +.Sh HISTORY +Those functions were designed and written for +.Ox +.Xr make 1 +by Marc Espie in 1999. diff --git a/lib/liboutil/ohash_interval.3 b/lib/liboutil/ohash_interval.3 @@ -0,0 +1,93 @@ +.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $ +.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 12 2014 $ +.Dt OHASH_INTERVAL 3 +.Os +.Sh NAME +.Nm ohash_interval , +.Nm ohash_create_entry , +.Nm ohash_qlookup , +.Nm ohash_qlookupi +.Nd helper functions for open hashing +.Sh SYNOPSIS +.In stdint.h +.In stddef.h +.In ohash.h +.Ft uint32_t +.Fn ohash_interval "const char *start" "const char **pend" +.Ft "void *" +.Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend" +.Ft "unsigned int" +.Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend" +.Ft "unsigned int" +.Fn ohash_qlookup "struct ohash *h" "const char *start" +.Sh DESCRIPTION +These functions are commonly used to simplify open hashing usage, and use +similar conventions. +They operate indifferently on NUL-terminated strings +.Po +by setting +.Fa *pend += +.Dv NULL +.Pc +or memory ranges +.Po +delimited by +.Fa start +and +.Fa *pend +.Pc . +For NUL-terminated strings, as a side effect, those functions +set +.Fa *pend +to the terminating NUL byte. +.Pp +.Fn ohash_interval +is a simple hashing function that yields good results on common data sets. +.Pp +.Fn ohash_create_entry +can be used to create a new record with a given key. +In that case, +the alloc field of +.Fa info +should point to a +.Xr malloc 3 Ns -like +function to allocate the storage: +.Bd -literal -offset indent +p = (*info->alloc)(sz, info->data); +.Ed +.Pp +.Fn ohash_qlookupi +is a wrapper function that simply calls +.Fn ohash_interval +and +.Fn ohash_lookup_interval . +.Pp +.Fn ohash_qlookup +is a variation on +.Fn ohash_qlookupi +designed for NUL-terminated strings. +.Sh SEE ALSO +.Xr ohash_init 3 +.Sh STANDARDS +Those functions are completely non-standard and should be avoided in +portable programs. +.Sh HISTORY +Those functions were designed and written for +.Ox +.Xr make 1 +by Marc Espie in 1999. diff --git a/lib/liboutil/pidfile.3 b/lib/liboutil/pidfile.3 @@ -0,0 +1,82 @@ +.\" $OpenBSD: pidfile.3,v 1.7 2013/06/05 03:40:26 tedu Exp $ +.\" $NetBSD: pidfile.3,v 1.2 2001/04/12 22:34:31 sommerfeld Exp $ +.\" +.\" Copyright (c) 1999 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd $Mdocdate: June 5 2013 $ +.Dt PIDFILE 3 +.Os +.Sh NAME +.Nm pidfile +.Nd write a daemon pid file +.Sh SYNOPSIS +.In util.h +.Ft int +.Fn pidfile "const char *basename" +.Sh DESCRIPTION +.Fn pidfile +writes a file containing the process ID of the program to the +.Pa /var/run +directory. +The file name has the form +.Pa /var/run/basename.pid . +If the +.Ar basename +argument is NULL, +.Nm +will determine the program name and use that instead. +.Pp +The pid file can be used as a quick reference if +the process needs to be sent a signal. +When the program exits, the pid file will be removed automatically, +unless the program receives a fatal signal. +.Sh RETURN VALUES +.Fn pidfile +returns 0 on success and -1 on failure. +.Sh SEE ALSO +.Xr atexit 3 +.Sh HISTORY +The +.Nm +function call appeared in +.Ox 3.0 . +.Sh CAVEATS +If +.Fn pidfile +is called multiple times with different +.Ar basename , +only the last pidfile will be removed upon exit. +.Pp +.Fn pidfile +uses +.Fn atexit +to ensure the pidfile is unlinked at program exit. +However, programs that use the +.Fn _exit +function (for example, in signal handlers) +will not trigger this behaviour. diff --git a/lib/liboutil/pidfile.c b/lib/liboutil/pidfile.c @@ -0,0 +1,105 @@ +/* $OpenBSD: pidfile.c,v 1.12 2015/11/27 01:57:59 mmcc Exp $ */ +/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <util.h> + +static char *pidfile_path; +static pid_t pidfile_pid; + +static void pidfile_cleanup(void); + +extern char *__progname; + +int +pidfile(const char *basename) +{ + int save_errno; + pid_t pid; + FILE *f; + + if (basename == NULL) + basename = __progname; + + free(pidfile_path); + pidfile_path = NULL; + + /* _PATH_VARRUN includes trailing / */ + if (asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename) == -1) + return (-1); + + if ((f = fopen(pidfile_path, "w")) == NULL) { + save_errno = errno; + free(pidfile_path); + pidfile_path = NULL; + errno = save_errno; + return (-1); + } + + pid = getpid(); + if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) { + save_errno = errno; + (void) fclose(f); + (void) unlink(pidfile_path); + free(pidfile_path); + pidfile_path = NULL; + errno = save_errno; + return (-1); + } + (void) fclose(f); + + pidfile_pid = pid; + if (atexit(pidfile_cleanup) < 0) { + save_errno = errno; + (void) unlink(pidfile_path); + free(pidfile_path); + pidfile_path = NULL; + pidfile_pid = 0; + errno = save_errno; + return (-1); + } + + return (0); +} + +static void +pidfile_cleanup(void) +{ + + if (pidfile_path != NULL && pidfile_pid == getpid()) + (void) unlink(pidfile_path); +} diff --git a/lib/liboutil/pkcs5_pbkdf2.3 b/lib/liboutil/pkcs5_pbkdf2.3 @@ -0,0 +1,63 @@ +.\" $OpenBSD: pkcs5_pbkdf2.3,v 1.5 2013/06/05 03:40:26 tedu Exp $ +.\" +.\" Copyright (c) 2012 Ted Unangst <tedu@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: June 5 2013 $ +.Dt PKCS5_PBKDF2 3 +.Os +.Sh NAME +.Nm pkcs5_pbkdf2 +.Nd password-based key derivation function +.Sh SYNOPSIS +.In util.h +.Ft int +.Fn pkcs5_pbkdf2 "const char *pass" "size_t pass_len" "const char *salt" \ + "size_t salt_len" "u_int8_t *key" "size_t key_len" "u_int rounds" +.Sh DESCRIPTION +The +.Nm +function converts a password into a byte array suitable for use as +an encryption key. +The password and salt values are combined and repeatedly hashed +.Ar rounds +times. +The salt value should be randomly generated beforehand. +The repeated hashing is designed to thwart discovery of the key via +password guessing attacks. +The higher the number of rounds, the slower each attempt will be. +A minimum value of at least 1000 is recommended. +.Sh RETURN VALUES +The +.Fn pkcs5_pbkdf2 +function returns 0 to indicate success and -1 for failure. +.\" .Sh EXAMPLES +.\" .Sh ERRORS +.Sh SEE ALSO +.Xr sha1 1 , +.Xr bcrypt_pbkdf 3 +.Sh STANDARDS +.Rs +.%A B. Kaliski +.%D September 2000 +.%R RFC 2898 +.%T PKCS #5: Password-Based Cryptography Specification Version 2.0 +.Re +.\" .Sh HISTORY +.\" .Sh AUTHORS +.Sh CAVEATS +The standard allows for different hash functions to be used. +This implementation only uses +.Xr sha1 1 . +.\" .Sh BUGS diff --git a/lib/liboutil/pkcs5_pbkdf2.c b/lib/liboutil/pkcs5_pbkdf2.c @@ -0,0 +1,122 @@ +/* $OpenBSD: pkcs5_pbkdf2.c,v 1.9 2015/02/05 12:59:57 millert Exp $ */ + +/*- + * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <util.h> + +#include <sha1.h> + +#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) + +/* + * HMAC-SHA-1 (from RFC 2202). + */ +static void +hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key, + size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH]) +{ + SHA1_CTX ctx; + u_int8_t k_pad[SHA1_BLOCK_LENGTH]; + u_int8_t tk[SHA1_DIGEST_LENGTH]; + int i; + + if (key_len > SHA1_BLOCK_LENGTH) { + SHA1Init(&ctx); + SHA1Update(&ctx, key, key_len); + SHA1Final(tk, &ctx); + + key = tk; + key_len = SHA1_DIGEST_LENGTH; + } + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < SHA1_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x36; + + SHA1Init(&ctx); + SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); + SHA1Update(&ctx, text, text_len); + SHA1Final(digest, &ctx); + + bzero(k_pad, sizeof k_pad); + bcopy(key, k_pad, key_len); + for (i = 0; i < SHA1_BLOCK_LENGTH; i++) + k_pad[i] ^= 0x5c; + + SHA1Init(&ctx); + SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); + SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH); + SHA1Final(digest, &ctx); +} + +/* + * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). + * Code based on IEEE Std 802.11-2007, Annex H.4.2. + */ +int +pkcs5_pbkdf2(const char *pass, size_t pass_len, const uint8_t *salt, + size_t salt_len, uint8_t *key, size_t key_len, unsigned int rounds) +{ + uint8_t *asalt, obuf[SHA1_DIGEST_LENGTH]; + uint8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH]; + unsigned int i, j; + unsigned int count; + size_t r; + + if (rounds < 1 || key_len == 0) + return -1; + if (salt_len == 0 || salt_len > SIZE_MAX - 4) + return -1; + if ((asalt = malloc(salt_len + 4)) == NULL) + return -1; + + memcpy(asalt, salt, salt_len); + + for (count = 1; key_len > 0; count++) { + asalt[salt_len + 0] = (count >> 24) & 0xff; + asalt[salt_len + 1] = (count >> 16) & 0xff; + asalt[salt_len + 2] = (count >> 8) & 0xff; + asalt[salt_len + 3] = count & 0xff; + hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1); + memcpy(obuf, d1, sizeof(obuf)); + + for (i = 1; i < rounds; i++) { + hmac_sha1(d1, sizeof(d1), pass, pass_len, d2); + memcpy(d1, d2, sizeof(d1)); + for (j = 0; j < sizeof(obuf); j++) + obuf[j] ^= d1[j]; + } + + r = MINIMUM(key_len, SHA1_DIGEST_LENGTH); + memcpy(key, obuf, r); + key += r; + key_len -= r; + }; + explicit_bzero(asalt, salt_len + 4); + free(asalt); + explicit_bzero(d1, sizeof(d1)); + explicit_bzero(d2, sizeof(d2)); + explicit_bzero(obuf, sizeof(obuf)); + + return 0; +} diff --git a/lib/liboutil/readlabel.c b/lib/liboutil/readlabel.c @@ -0,0 +1,144 @@ +/* $OpenBSD: readlabel.c,v 1.13 2015/01/16 16:48:52 deraadt Exp $ */ + +/* + * Copyright (c) 1996, Jason Downs. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/disk.h> +#include <sys/dkio.h> +#define DKTYPENAMES +#include <sys/disklabel.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <stdio.h> +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <fcntl.h> +#include <paths.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +/* + * Try to get a disklabel for the specified device, and return mount_xxx + * style filesystem type name for the specified partition. + */ +char * +readlabelfs(char *device, int verbose) +{ + char rpath[PATH_MAX]; + struct dk_diskmap dm; + struct disklabel dk; + char part, *type; + struct stat sbuf; + int fd = -1; + + /* Perform disk mapping if device is given as a DUID. */ + if (isduid(device, 0)) { + if ((fd = open("/dev/diskmap", O_RDONLY)) != -1) { + bzero(&dm, sizeof(struct dk_diskmap)); + strlcpy(rpath, device, sizeof(rpath)); + part = rpath[strlen(rpath) - 1]; + dm.device = rpath; + dm.fd = fd; + dm.flags = DM_OPENPART; + if (ioctl(fd, DIOCMAP, &dm) == -1) + close(fd); + else + goto disklabel; + } + } + + /* Assuming device is of the form /dev/??p, build a raw partition. */ + if (stat(device, &sbuf) < 0) { + if (verbose) + warn("%s", device); + return (NULL); + } + switch (sbuf.st_mode & S_IFMT) { + case S_IFCHR: + /* Ok... already a raw device. Hmm. */ + strlcpy(rpath, device, sizeof(rpath)); + + /* Change partition name. */ + part = rpath[strlen(rpath) - 1]; + rpath[strlen(rpath) - 1] = 'a' + getrawpartition(); + break; + case S_IFBLK: + if (strlen(device) > sizeof(_PATH_DEV) - 1) { + snprintf(rpath, sizeof(rpath), "%sr%s", _PATH_DEV, + &device[sizeof(_PATH_DEV) - 1]); + /* Change partition name. */ + part = rpath[strlen(rpath) - 1]; + rpath[strlen(rpath) - 1] = 'a' + getrawpartition(); + break; + } + /* FALLTHROUGH */ + default: + if (verbose) + warnx("%s: not a device node", device); + return (NULL); + } + + /* If rpath doesn't exist, change that partition back. */ + fd = open(rpath, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) { + rpath[strlen(rpath) - 1] = part; + + fd = open(rpath, O_RDONLY); + if (fd < 0) { + if (verbose) + warn("%s", rpath); + return (NULL); + } + } else { + if (verbose) + warn("%s", rpath); + return (NULL); + } + } + +disklabel: + + if (ioctl(fd, DIOCGDINFO, &dk) < 0) { + if (verbose) + warn("%s: couldn't read disklabel", rpath); + close(fd); + return (NULL); + } + close(fd); + + if (dk.d_partitions[part - 'a'].p_fstype >= FSMAXTYPES) { + if (verbose) + warnx("%s: bad filesystem type in label", rpath); + return (NULL); + } + + type = fstypesnames[dk.d_partitions[part - 'a'].p_fstype]; + return ((type[0] == '\0') ? NULL : type); +} diff --git a/lib/liboutil/readlabelfs.3 b/lib/liboutil/readlabelfs.3 @@ -0,0 +1,61 @@ +.\" $OpenBSD: readlabelfs.3,v 1.8 2013/06/05 03:40:26 tedu Exp $ +.\" +.\" Copyright (c) 1996, Jason Downs. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS +.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd $Mdocdate: June 5 2013 $ +.Dt READLABELFS 3 +.Os +.Sh NAME +.Nm readlabelfs +.Nd read disklabel filesystem type +.Sh SYNOPSIS +.In util.h +.Ft char * +.Fn readlabelfs "char *device" "int verbose" +.Sh DESCRIPTION +The +.Fn readlabelfs +function attempts to determine the filesystem type of the disk +partition specified by +.Fa device +and returns it in a short form that can be easily used to construct +arguments within +.Xr mount 8 +and similar high-level filesystem utilities. +.Pp +If the +.Fa verbose +argument is not 0, +.Fn readlabelfs +will print appropriate error messages before returning. +Otherwise, it produces no output on the terminal. +.Sh RETURN VALUES +.Fn readlabelfs +returns +.Dv NULL +upon error, or a valid filesystem type upon success. +.Sh HISTORY +.Fn readlabelfs +first appeared in +.Ox 2.0 . diff --git a/lib/liboutil/shlib_version b/lib/liboutil/shlib_version @@ -0,0 +1,2 @@ +major=12 +minor=1 diff --git a/lib/liboutil/util.h b/lib/liboutil/util.h @@ -0,0 +1,91 @@ +/* $OpenBSD: util.h,v 1.34 2013/06/03 21:07:02 tedu Exp $ */ +/* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */ + +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * Portions Copyright (c) 1996, Jason Downs. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include <sys/types.h> +#include <stdio.h> + +/* + * fparseln() specific operation flags. + */ +#define FPARSELN_UNESCESC 0x01 +#define FPARSELN_UNESCCONT 0x02 +#define FPARSELN_UNESCCOMM 0x04 +#define FPARSELN_UNESCREST 0x08 +#define FPARSELN_UNESCALL 0x0f + +/* + * uucplock(3) specific flags. + */ +#define UU_LOCK_INUSE (1) +#define UU_LOCK_OK (0) +#define UU_LOCK_OPEN_ERR (-1) +#define UU_LOCK_READ_ERR (-2) +#define UU_LOCK_CREAT_ERR (-3) +#define UU_LOCK_WRITE_ERR (-4) +#define UU_LOCK_LINK_ERR (-5) +#define UU_LOCK_TRY_ERR (-6) +#define UU_LOCK_OWNER_ERR (-7) + +/* + * fmt_scaled(3) specific flags. + */ +#define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ + +/* + * stub struct definitions. + */ +struct termios; +struct utmp; +struct winsize; + +__BEGIN_DECLS +char *fparseln(FILE *, size_t *, size_t *, const char[3], int); +void logwtmp(const char *, const char *, const char *); +int pidfile(const char *); +const char *uu_lockerr(int); +int uu_lock(const char *); +int uu_lock_txfr(const char *, pid_t); +int uu_unlock(const char *); +int fmt_scaled(long long, char *); +int scan_scaled(char *, long long *); +int pkcs5_pbkdf2(const char *, size_t, const uint8_t *, size_t, + uint8_t *, size_t, unsigned int); +int bcrypt_pbkdf(const char *, size_t, const uint8_t *, size_t, + uint8_t *, size_t, unsigned int); + +__END_DECLS + +#endif /* !_UTIL_H_ */ diff --git a/lib/liboutil/uucplock.3 b/lib/liboutil/uucplock.3 @@ -0,0 +1,178 @@ +.\" $OpenBSD: uucplock.3,v 1.19 2015/11/10 23:48:18 jmc Exp $ +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" " +.Dd $Mdocdate: November 10 2015 $ +.Dt UU_LOCK 3 +.Os +.Sh NAME +.Nm uu_lock , +.Nm uu_unlock , +.Nm uu_lockerr , +.Nm uu_lock_txfr +.Nd acquire and release control of a serial device +.Sh SYNOPSIS +.In sys/types.h +.In util.h +.Ft int +.Fn uu_lock "const char *ttyname" +.Ft int +.Fn uu_lock_txfr "const char *ttyname" "pid_t pid" +.Ft int +.Fn uu_unlock "const char *ttyname" +.Ft const char * +.Fn uu_lockerr "int uu_lockresult" +.Sh DESCRIPTION +The +.Fn uu_lock +function attempts to create a lock file called +.Pa /var/spool/lock/LCK.. +with a suffix given by the passed +.Fa ttyname . +If the file already exists, it is expected to contain the process +ID of the locking program. +.Pp +If the file does not already exist, or the owning process given by +the process ID found in the lock file is no longer running, +.Fn uu_lock +will write its own process ID into the file and return success. +.Pp +.Fn uu_lock_txfr +transfers lock ownership to another process. +.Fn uu_lock +must have previously been successful. +.Pp +.Fn uu_unlock +removes the lockfile created by +.Fn uu_lock +for the given +.Fa ttyname . +Care should be taken that +.Fn uu_lock +was successful before calling +.Fn uu_unlock . +.Pp +.Fn uu_lockerr +returns an error string representing the error +.Fa uu_lockresult , +as returned from +.Fn uu_lock . +.Sh RETURN VALUES +.Fn uu_unlock +returns 0 on success and \-1 on failure. +.Pp +.Fn uu_lock +may return any of the following values: +.Pp +.Dv UU_LOCK_INUSE : +The lock is in use by another process. +.Pp +.Dv UU_LOCK_OK : +The lock was successfully created. +.Pp +.Dv UU_LOCK_OPEN_ERR : +The lock file could not be opened via +.Xr open 2 . +.Pp +.Dv UU_LOCK_READ_ERR : +The lock file could not be read via +.Xr read 2 . +.Pp +.Dv UU_LOCK_CREAT_ERR : +Can't create temporary lock file via +.Xr creat 3 . +.Pp +.Dv UU_LOCK_WRITE_ERR : +The current process ID could not be written to the lock file via a call to +.Xr write 2 . +.Pp +.Dv UU_LOCK_LINK_ERR : +Can't link temporary lock file via +.Xr link 2 . +.Pp +.Dv UU_LOCK_TRY_ERR : +Locking attempts are failed after 5 tries. +.Pp +If a value of +.Dv UU_LOCK_OK +is passed to +.Fn uu_lockerr , +an empty string is returned. +Otherwise, a string specifying +the reason for failure is returned. +.Fn uu_lockerr +uses the current value of +.Va errno +to determine the exact error. +Care should be made not to allow +.Va errno +to be changed between calls to +.Fn uu_lock +and +.Fn uu_lockerr . +.Pp +.Fn uu_lock_txfr +may return any of the following values: +.Pp +.Dv UU_LOCK_OK : +The transfer was successful. +The specified process now holds the device lock. +.Pp +.Dv UU_LOCK_OWNER_ERR : +The current process does not already own a lock on the specified device. +.Pp +.Dv UU_LOCK_WRITE_ERR : +The new process ID could not be written to the lock file via a call to +.Xr write 2 . +.Sh ERRORS +If +.Fn uu_lock +returns one of the error values above, the global value +.Va errno +can be used to determine the cause. +Refer to the respective manual pages for further details. +.Pp +.Fn uu_unlock +will set the global variable +.Va errno +to reflect the reason that the lock file could not be removed. +Refer to the description of +.Xr unlink 2 +for further details. +.Sh SEE ALSO +.Xr lseek 2 , +.Xr open 2 , +.Xr read 2 , +.Xr write 2 +.Sh BUGS +It is possible that a stale lock is not recognised as such if a new +process is assigned the same process ID as the program that left +the stale lock. +.Pp +The calling process must have write permissions to the +.Pa /var/spool/lock +directory. +There is no mechanism in place to ensure that the +permissions of this directory are the same as those of the +serial devices that might be locked. diff --git a/lib/liboutil/uucplock.c b/lib/liboutil/uucplock.c @@ -0,0 +1,225 @@ +/* $OpenBSD: uucplock.c,v 1.17 2015/11/11 01:12:09 deraadt Exp $ */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <paths.h> +#include <string.h> +#include "util.h" + +#define MAXTRIES 5 + +#define LOCKTMP "LCKTMP..%ld" +#define LOCKFMT "LCK..%s" + +#define GORET(level, val) { err = errno; uuerr = (val); \ + goto __CONCAT(ret, level); } + +/* Forward declarations */ +static int put_pid(int fd, pid_t pid); +static pid_t get_pid(int fd,int *err); + +/* + * uucp style locking routines + */ +int +uu_lock(const char *ttyname) +{ + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], + lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + int fd, tmpfd, i, err, uuerr; + pid_t pid, pid_old; + + pid = getpid(); + (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, + (long)pid); + (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, + ttyname); + if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY, 0664)) < 0) + GORET(0, UU_LOCK_CREAT_ERR); + + for (i = 0; i < MAXTRIES; i++) { + if (link(lcktmpname, lckname) < 0) { + if (errno != EEXIST) + GORET(1, UU_LOCK_LINK_ERR); + /* + * file is already locked + * check to see if the process holding the lock + * still exists + */ + if ((fd = open(lckname, O_RDONLY)) < 0) + GORET(1, UU_LOCK_OPEN_ERR); + + if ((pid_old = get_pid(fd, &err)) == -1) + GORET(2, UU_LOCK_READ_ERR); + + close(fd); + + if (kill(pid_old, 0) == 0 || errno != ESRCH) + GORET(1, UU_LOCK_INUSE); + /* + * The process that locked the file isn't running, so + * we'll lock it ourselves + */ + (void)unlink(lckname); + } else { + if (!put_pid(tmpfd, pid)) + GORET(3, UU_LOCK_WRITE_ERR); + break; + } + } + GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); + +ret3: + (void)unlink(lckname); + goto ret1; +ret2: + (void)close(fd); +ret1: + (void)close(tmpfd); + (void)unlink(lcktmpname); +ret0: + errno = err; + return uuerr; +} + +int +uu_lock_txfr(const char *ttyname, pid_t pid) +{ + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + int fd, err, ret; + + snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname); + + if ((fd = open(lckname, O_RDWR)) < 0) + return UU_LOCK_OWNER_ERR; + if (get_pid(fd, &err) != getpid()) + ret = UU_LOCK_OWNER_ERR; + else { + lseek(fd, 0, SEEK_SET); + ret = put_pid(fd, pid) ? UU_LOCK_OK : UU_LOCK_WRITE_ERR; + } + + close(fd); + return ret; +} + +int +uu_unlock(const char *ttyname) +{ + char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + + (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); + return unlink(tbuf); +} + +const char * +uu_lockerr(int uu_lockresult) +{ + static char errbuf[128]; + char *fmt; + + switch (uu_lockresult) { + case UU_LOCK_INUSE: + return "device in use"; + case UU_LOCK_OK: + return ""; + case UU_LOCK_OPEN_ERR: + fmt = "open error: %s"; + break; + case UU_LOCK_READ_ERR: + fmt = "read error: %s"; + break; + case UU_LOCK_CREAT_ERR: + fmt = "creat error: %s"; + break; + case UU_LOCK_WRITE_ERR: + fmt = "write error: %s"; + break; + case UU_LOCK_LINK_ERR: + fmt = "link error: %s"; + break; + case UU_LOCK_TRY_ERR: + fmt = "too many tries: %s"; + break; + case UU_LOCK_OWNER_ERR: + fmt = "not locking process: %s"; + break; + default: + fmt = "undefined error: %s"; + break; + } + + (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno)); + return errbuf; +} + +static int +put_pid(int fd, pid_t pid) +{ + char buf[32]; + int len; + + len = snprintf(buf, sizeof buf, "%10ld\n", (long)pid); + + if (len < sizeof buf && len != -1 && write(fd, buf, (size_t)len) == len) { + /* We don't mind too much if ftruncate() fails - see get_pid */ + ftruncate(fd, (off_t)len); + return 1; + } + return 0; +} + +static pid_t +get_pid(int fd, int *err) +{ + ssize_t bytes_read; + char buf[32]; + pid_t pid; + + bytes_read = read(fd, buf, sizeof (buf) - 1); + if (bytes_read > 0) { + buf[bytes_read] = '\0'; + pid = (pid_t)strtoul(buf, (char **) NULL, 10); + } else { + pid = -1; + *err = bytes_read ? errno : EINVAL; + } + return pid; +} diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile @@ -1,35 +0,0 @@ -# $OpenBSD: Makefile,v 1.39 2016/03/30 06:38:43 jmc Exp $ -# $NetBSD: Makefile,v 1.8 1996/05/16 07:03:28 thorpej Exp $ - -.TOPDIR?=../.. -.CURDIR?=. - -LIB= util -CPPFLAGS+=-D_GNU_SOURCE - -HDRS= util.h imsg.h -SRCS= bcrypt_pbkdf.c \ - logwtmp.c \ - uucplock.c fparseln.c pidfile.c \ - fmt_scaled.c imsg.c imsg-buffer.c pkcs5_pbkdf2.c - -MAN= bcrypt_pbkdf.3 \ - uucplock.3 \ - fparseln.3 pidfile.3 fmt_scaled.3 imsg_init.3 \ - pkcs5_pbkdf2.3 - -SRCS+= ohash.c -HDRS += ohash.h - -MAN += ohash_init.3 ohash_interval.3 - -includes: - @cd ${.CURDIR}; for i in $(HDRS); do \ - j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \ - ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} \ - -m 444 $$i ${DESTDIR}/usr/include"; \ - echo $$j; \ - eval "$$j"; \ - done - -include ${.TOPDIR}/mk/bsd.lib.mk diff --git a/lib/libutil/bcrypt_pbkdf.3 b/lib/libutil/bcrypt_pbkdf.3 @@ -1,69 +0,0 @@ -.\" $OpenBSD: bcrypt_pbkdf.3,v 1.6 2014/11/25 03:37:12 tedu Exp $ -.\" -.\" Copyright (c) 2012 Ted Unangst <tedu@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: November 25 2014 $ -.Dt BCRYPT_PBKDF 3 -.Os -.Sh NAME -.Nm bcrypt_pbkdf -.Nd bcrypt password-based key derivation function -.Sh SYNOPSIS -.In util.h -.Ft int -.Fn bcrypt_pbkdf "const char *pass" "size_t pass_len" "const uint8_t *salt" \ - "size_t salt_len" "uint8_t *key" "size_t key_len" "unsigned int rounds" -.Sh DESCRIPTION -The -.Nm -function converts a password into a byte array suitable for use as -an encryption key. -The password and salt values are combined and repeatedly hashed -.Ar rounds -times. -The salt value should be randomly generated beforehand. -The repeated hashing is designed to thwart discovery of the key via -password guessing attacks. -The higher the number of rounds, the slower each attempt will be. -.\" A minimum value of at least 4 is recommended. -.Sh RETURN VALUES -The -.Fn bcrypt_pbkdf -function returns 0 to indicate success and \-1 for failure. -.\" .Sh EXAMPLES -.\" .Sh ERRORS -.Sh SEE ALSO -.Xr bcrypt 3 -.Sh STANDARDS -.Rs -.%A Niels Provos and David Mazieres -.%D June 1999 -.%T A Future-Adaptable Password Scheme -.Re -.Pp -.Rs -.%A B. Kaliski -.%D September 2000 -.%R RFC 2898 -.%T PKCS #5: Password-Based Cryptography Specification Version 2.0 -.Re -.\" .Sh HISTORY -.\" .Sh AUTHORS -.Sh CAVEATS -This implementation deviates slightly from the PBKDF2 standard by mixing -output key bits nonlinearly. -By mixing the output bytes together, an attacker is required to perform -all of the work without taking any shortcuts. -.\" .Sh BUGS diff --git a/lib/libutil/bcrypt_pbkdf.c b/lib/libutil/bcrypt_pbkdf.c @@ -1,169 +0,0 @@ -/* $OpenBSD: bcrypt_pbkdf.c,v 1.13 2015/01/12 03:20:04 tedu Exp $ */ -/* - * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> - -#include <stdint.h> -#include <stdlib.h> -#include <blf.h> -#include <sha2.h> -#include <string.h> -#include <util.h> - -#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) - -/* - * pkcs #5 pbkdf2 implementation using the "bcrypt" hash - * - * The bcrypt hash function is derived from the bcrypt password hashing - * function with the following modifications: - * 1. The input password and salt are preprocessed with SHA512. - * 2. The output length is expanded to 256 bits. - * 3. Subsequently the magic string to be encrypted is lengthened and modifed - * to "OxychromaticBlowfishSwatDynamite" - * 4. The hash function is defined to perform 64 rounds of initial state - * expansion. (More rounds are performed by iterating the hash.) - * - * Note that this implementation pulls the SHA512 operations into the caller - * as a performance optimization. - * - * One modification from official pbkdf2. Instead of outputting key material - * linearly, we mix it. pbkdf2 has a known weakness where if one uses it to - * generate (e.g.) 512 bits of key material for use as two 256 bit keys, an - * attacker can merely run once through the outer loop, but the user - * always runs it twice. Shuffling output bytes requires computing the - * entirety of the key material to assemble any subkey. This is something a - * wise caller could do; we just do it for you. - */ - -#define BCRYPT_WORDS 8 -#define BCRYPT_HASHSIZE (BCRYPT_WORDS * 4) - -static void -bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) -{ - blf_ctx state; - uint8_t ciphertext[BCRYPT_HASHSIZE] = - "OxychromaticBlowfishSwatDynamite"; - uint32_t cdata[BCRYPT_WORDS]; - int i; - uint16_t j; - size_t shalen = SHA512_DIGEST_LENGTH; - - /* key expansion */ - Blowfish_initstate(&state); - Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen); - for (i = 0; i < 64; i++) { - Blowfish_expand0state(&state, sha2salt, shalen); - Blowfish_expand0state(&state, sha2pass, shalen); - } - - /* encryption */ - j = 0; - for (i = 0; i < BCRYPT_WORDS; i++) - cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), - &j); - for (i = 0; i < 64; i++) - blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); - - /* copy out */ - for (i = 0; i < BCRYPT_WORDS; i++) { - out[4 * i + 3] = (cdata[i] >> 24) & 0xff; - out[4 * i + 2] = (cdata[i] >> 16) & 0xff; - out[4 * i + 1] = (cdata[i] >> 8) & 0xff; - out[4 * i + 0] = cdata[i] & 0xff; - } - - /* zap */ - explicit_bzero(ciphertext, sizeof(ciphertext)); - explicit_bzero(cdata, sizeof(cdata)); - explicit_bzero(&state, sizeof(state)); -} - -int -bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, - uint8_t *key, size_t keylen, unsigned int rounds) -{ - SHA2_CTX ctx; - uint8_t sha2pass[SHA512_DIGEST_LENGTH]; - uint8_t sha2salt[SHA512_DIGEST_LENGTH]; - uint8_t out[BCRYPT_HASHSIZE]; - uint8_t tmpout[BCRYPT_HASHSIZE]; - uint8_t countsalt[4]; - size_t i, j, amt, stride; - uint32_t count; - size_t origkeylen = keylen; - - /* nothing crazy */ - if (rounds < 1) - return -1; - if (passlen == 0 || saltlen == 0 || keylen == 0 || - keylen > sizeof(out) * sizeof(out)) - return -1; - stride = (keylen + sizeof(out) - 1) / sizeof(out); - amt = (keylen + stride - 1) / stride; - - /* collapse password */ - SHA512Init(&ctx); - SHA512Update(&ctx, pass, passlen); - SHA512Final(sha2pass, &ctx); - - - /* generate key, sizeof(out) at a time */ - for (count = 1; keylen > 0; count++) { - countsalt[0] = (count >> 24) & 0xff; - countsalt[1] = (count >> 16) & 0xff; - countsalt[2] = (count >> 8) & 0xff; - countsalt[3] = count & 0xff; - - /* first round, salt is salt */ - SHA512Init(&ctx); - SHA512Update(&ctx, salt, saltlen); - SHA512Update(&ctx, countsalt, sizeof(countsalt)); - SHA512Final(sha2salt, &ctx); - bcrypt_hash(sha2pass, sha2salt, tmpout); - memcpy(out, tmpout, sizeof(out)); - - for (i = 1; i < rounds; i++) { - /* subsequent rounds, salt is previous output */ - SHA512Init(&ctx); - SHA512Update(&ctx, tmpout, sizeof(tmpout)); - SHA512Final(sha2salt, &ctx); - bcrypt_hash(sha2pass, sha2salt, tmpout); - for (j = 0; j < sizeof(out); j++) - out[j] ^= tmpout[j]; - } - - /* - * pbkdf2 deviation: output the key material non-linearly. - */ - amt = MINIMUM(amt, keylen); - for (i = 0; i < amt; i++) { - size_t dest = i * stride + (count - 1); - if (dest >= origkeylen) - break; - key[dest] = out[i]; - } - keylen -= i; - } - - /* zap */ - explicit_bzero(&ctx, sizeof(ctx)); - explicit_bzero(out, sizeof(out)); - - return 0; -} diff --git a/lib/libutil/check_expire.3 b/lib/libutil/check_expire.3 @@ -1,62 +0,0 @@ -.\" $OpenBSD: check_expire.3,v 1.10 2014/12/04 18:25:46 schwarze Exp $ -.\" -.\" Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: December 4 2014 $ -.Dt LOGIN_CHECK_EXPIRE 3 -.Os -.Sh NAME -.Nm login_check_expire -.Nd check for password expiration -.Sh SYNOPSIS -.In stdio.h -.In util.h -.Ft int -.Fn login_check_expire "FILE *back" "struct passwd *pwd" "char *class" "int lastchance" -.Sh DESCRIPTION -The -.Fn login_check_expire -function is called by a -.Bx -Authentication login script to -check whether the user's password entry, as described by -.Fa pwd , -has expired. -.Pp -If a -.Fa class -is specified, it is used instead of the class specified in the user's -password database entry. -If the -.Fa lastchance -argument is non-zero, the user's password has expired, and it has not been -expired longer than -.Dq password-dead -seconds (see -.Xr login.conf 5 ) , -the user will be able to log in one last time to change the password. -.Sh RETURN VALUES -The -.Fn login_check_expire -function returns 0 if the user's password has not expired, and 1 if it has -expired or if an error occurred. -.br -Status and error messages are passed -back to the login script caller via the back channel, -.Fa back . -.Sh SEE ALSO -.Xr auth_subr 3 , -.Xr authenticate 3 , -.Xr login.conf 5 diff --git a/lib/libutil/check_expire.c b/lib/libutil/check_expire.c @@ -1,189 +0,0 @@ -/* $OpenBSD: check_expire.c,v 1.12 2015/11/26 23:32:52 millert Exp $ */ - -/* - * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Berkeley Software Design, - * Inc. - * 4. The name of Berkeley Software Design, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * BSDI $From: check_expire.c,v 2.1 1997/08/08 18:38:25 prb Exp $ - */ - -#include <sys/types.h> - -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <login_cap.h> -#include <bsd_auth.h> - -#include "util.h" - -static char *pwd_update(const struct passwd *, const struct passwd *); - -#define SECSPERDAY (24 * 60 * 60) -#define TWOWEEKS (2 * 7 * SECSPERDAY) - -int -login_check_expire(FILE *back, struct passwd *pwd, char *class, int lastchance) -{ - auth_session_t *as; - login_cap_t *lc; - quad_t dead, expire, warn; - char *p; - - if ((as = auth_open()) == NULL) { - fprintf(back, BI_VALUE - " errormsg Unable to create auth session\n"); - fprintf(back, BI_REJECT "\n"); - return (1); - } - if (auth_setpwd(as, pwd) < 0) { - fprintf(back, BI_VALUE - " errormsg Unable to set pwd entry in auth session\n"); - fprintf(back, BI_REJECT "\n"); - return (1); - } - - expire = auth_check_change(as); - auth_close(as); - - if (expire != 0) { - fprintf(back, BI_VALUE " expire %qd\n", expire); - - if (class == NULL) - class = pwd->pw_class; - - if ((lc = login_getclass(class)) == NULL) { - dead = 0; - warn = 0; - } else { - dead = login_getcaptime(lc, "password-dead", 0, 0); - warn = login_getcaptime(lc, "password-warn", - TWOWEEKS, TWOWEEKS); - if (dead < 0) - dead = 0; - if (warn < 0) - warn = 0; - } - login_close(lc); - - /* - * If their password is dead (expired longer than - * password-dead) then just reject them. If it is - * expired but not dead yet, reject them with a - * PWEXPIRED so login knows they can still sort of - * get in. - */ - if (expire < -dead) { - fprintf(back, BI_VALUE - " errormsg Your password has expired\n"); - fprintf(back, BI_REJECT "\n"); - return (1); - } - if (expire < 0) { - if (lastchance) { - struct passwd *npwd; - - endpwent(); - - /* - * Only let them play this game once. - * Set their password change time to 1. - * This will most certainly cause any - * expired password to be dead, as well. - */ - npwd = pw_dup(pwd); - npwd->pw_change = 1; - p = pwd_update(npwd, pwd); - explicit_bzero(npwd->pw_passwd, - strlen(npwd->pw_passwd)); - free(npwd); - if (p != NULL) { - char *errval = auth_mkvalue(p); - if (errval != NULL) { - fprintf(back, BI_VALUE - " errormsg %s", errval); - free(errval); - } - fprintf(back, BI_REJECT "\n"); - return (1); - } - } - fprintf(back, BI_VALUE - " errormsg Your password has expired\n"); - fprintf(back, BI_PWEXPIRED "\n"); - return (1); - } - - /* - * If their password is not expired but is about to expire - * then warn them. - */ - if (expire <= warn) { - fprintf(back, BI_VALUE - " warnmsg Your password expires on %s\n", - ctime(&pwd->pw_change)); - } - } - return (0); -} - -static char * -pwd_update(const struct passwd *pwd, const struct passwd *opwd) -{ - int tfd, pfd; - - pw_init(); - tfd = pw_lock(0); - if (tfd < 0) { - if (errno == EEXIST) - return("the passwd file is busy."); - else - return("can't open passwd temp file"); - } - - pfd = open(_PATH_MASTERPASSWD, O_RDONLY|O_CLOEXEC, 0); - if (pfd < 0) { - pw_abort(); - return(strerror(errno)); - } - - pw_copy(pfd, tfd, pwd, opwd); - if (pw_mkdb(pwd->pw_name, 0) < 0) { - pw_abort(); - return("unable to update password database"); - } - - return(NULL); -} diff --git a/lib/libutil/fmt_scaled.3 b/lib/libutil/fmt_scaled.3 @@ -1,134 +0,0 @@ -.\" $OpenBSD: fmt_scaled.3,v 1.8 2016/07/16 16:10:44 jca Exp $ -.\" Copyright (c) 2001, 2003 Ian Darwin. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd $Mdocdate: July 16 2016 $ -.Dt FMT_SCALED 3 -.Os -.Sh NAME -.Nm fmt_scaled , -.Nm scan_scaled -.Nd handle numbers with a human-readable scale -.Sh SYNOPSIS -.In util.h -.Ft int -.Fn scan_scaled "char *number_w_scale" "long long *result" -.Ft int -.Fn fmt_scaled "long long number" "char *result" -.Sh DESCRIPTION -The -.Fn scan_scaled -function scans the given number and looks for a terminal scale multiplier -of B, K, M, G, T, P or E -.Pq in either upper or lower case -for Byte, Kilobyte, Megabyte, Gigabyte, Terabyte, Petabyte, Exabyte -.Po computed using powers of two, i.e., Megabyte = 1024*1024 -.Pc . -The number can have a decimal point, as in 1.5K, which returns 1536 -.Pq 1024+512 . -If no scale factor is found, B is assumed. -.Pp -The -.Fn fmt_scaled -function formats a number for display using the same -"human-readable" format, that is, a number with one of the above scale factors. -Numbers will be printed with a maximum of four digits (preceded by -a minus sign if the value is negative); values such -as 0B, 100B, 1023B, 1K, 1.5K, 5.5M, and so on, will be generated. -The -.Qq result -buffer must be allocated with at least -.Dv FMT_SCALED_STRSIZE -bytes. -The result will be left-justified in the given space, and NUL-terminated. -.Sh RETURN VALUES -The -.Fn scan_scaled -and -.Fn fmt_scaled -functions -return 0 on success. -In case of error, they return \-1, leave -.Va *result -as is, and set -.Va errno -to one of the following values: -.Dv ERANGE -if the input string represents a number that is too large to represent. -.Dv EINVAL -if an unknown character was used as scale factor, or -if the input to -.Fn scan_scaled -was malformed, e.g., too many '.' characters. -.Sh EXAMPLES -.Bd -literal -offset indent -char *cinput = "1.5K"; -long long result; -if (scan_scaled(cinput, &result) == 0) - printf("%s -> %lld\en", cinput, result); -else - fprintf(stderr, "%s - invalid\en", cinput); - -char buf[FMT_SCALED_STRSIZE]; -long long ninput = 10483892; -if (fmt_scaled(ninput, buf) == 0) - printf("%lld -> %s\en", ninput, buf); -else - fprintf(stderr, "fmt scaled failed (errno %d)", errno); -.Ed -.Sh SEE ALSO -.Xr printf 3 , -.Xr scanf 3 -.Sh HISTORY -The functions -.Fn fmt_scaled -and -.Fn scan_scaled -first appeared in -.Ox 3.4 . -.Sh AUTHORS -.An -nosplit -.An Ken Stailey -wrote the first version of the code that became -.Fn fmt_scaled , -originally inside -.Ox -.Xr df 1 . -.An Ian Darwin -excerpted this and made it into a library routine -(with significant help from -.An Paul Janzen ) , -and wrote -.Fn scan_scaled . -.Sh BUGS -Some of the scale factors have misleading meanings in lower case -(p for P is incorrect; p should be pico- and P for Peta-). -However, we bend the SI rules in favor of common sense here. -A person creating a disk partition of "100m" is unlikely to require -100 millibytes (i.e., 0.1 byte) of storage in the partition; -100 megabytes is the only reasonable interpretation. -.Pp -Cannot represent the larger scale factors on all architectures. -.Pp -Ignores the current locale. diff --git a/lib/libutil/fmt_scaled.c b/lib/libutil/fmt_scaled.c @@ -1,271 +0,0 @@ -/* $OpenBSD: fmt_scaled.c,v 1.12 2013/11/29 19:00:51 deraadt Exp $ */ - -/* - * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * fmt_scaled: Format numbers scaled for human comprehension - * scan_scaled: Scan numbers in this format. - * - * "Human-readable" output uses 4 digits max, and puts a unit suffix at - * the end. Makes output compact and easy-to-read esp. on huge disks. - * Formatting code was originally in OpenBSD "df", converted to library routine. - * Scanning code written for OpenBSD libutil. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <limits.h> - -#include "util.h" - -typedef enum { - NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 -} unit_type; - -/* These three arrays MUST be in sync! XXX make a struct */ -static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; -static char scale_chars[] = "BKMGTPE"; -static long long scale_factors[] = { - 1LL, - 1024LL, - 1024LL*1024, - 1024LL*1024*1024, - 1024LL*1024*1024*1024, - 1024LL*1024*1024*1024*1024, - 1024LL*1024*1024*1024*1024*1024, -}; -#define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) - -#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ - -/* Convert the given input string "scaled" into numeric in "result". - * Return 0 on success, -1 and errno set on error. - */ -int -scan_scaled(char *scaled, long long *result) -{ - char *p = scaled; - int sign = 0; - unsigned int i, ndigits = 0, fract_digits = 0; - long long scale_fact = 1, whole = 0, fpart = 0; - - /* Skip leading whitespace */ - while (isascii((unsigned char)*p) && isspace((unsigned char)*p)) - ++p; - - /* Then at most one leading + or - */ - while (*p == '-' || *p == '+') { - if (*p == '-') { - if (sign) { - errno = EINVAL; - return -1; - } - sign = -1; - ++p; - } else if (*p == '+') { - if (sign) { - errno = EINVAL; - return -1; - } - sign = +1; - ++p; - } - } - - /* Main loop: Scan digits, find decimal point, if present. - * We don't allow exponentials, so no scientific notation - * (but note that E for Exa might look like e to some!). - * Advance 'p' to end, to get scale factor. - */ - for (; isascii((unsigned char)*p) && - (isdigit((unsigned char)*p) || *p=='.'); ++p) { - if (*p == '.') { - if (fract_digits > 0) { /* oops, more than one '.' */ - errno = EINVAL; - return -1; - } - fract_digits = 1; - continue; - } - - i = (*p) - '0'; /* whew! finally a digit we can use */ - if (fract_digits > 0) { - if (fract_digits >= MAX_DIGITS-1) - /* ignore extra fractional digits */ - continue; - fract_digits++; /* for later scaling */ - fpart *= 10; - fpart += i; - } else { /* normal digit */ - if (++ndigits >= MAX_DIGITS) { - errno = ERANGE; - return -1; - } - whole *= 10; - whole += i; - } - } - - if (sign) { - whole *= sign; - fpart *= sign; - } - - /* If no scale factor given, we're done. fraction is discarded. */ - if (!*p) { - *result = whole; - return 0; - } - - /* Validate scale factor, and scale whole and fraction by it. */ - for (i = 0; i < SCALE_LENGTH; i++) { - - /* Are we there yet? */ - if (*p == scale_chars[i] || - *p == tolower((unsigned char)scale_chars[i])) { - - /* If it ends with alphanumerics after the scale char, bad. */ - if (isalnum((unsigned char)*(p+1))) { - errno = EINVAL; - return -1; - } - scale_fact = scale_factors[i]; - - /* scale whole part */ - whole *= scale_fact; - - /* truncate fpart so it does't overflow. - * then scale fractional part. - */ - while (fpart >= LLONG_MAX / scale_fact) { - fpart /= 10; - fract_digits--; - } - fpart *= scale_fact; - if (fract_digits > 0) { - for (i = 0; i < fract_digits -1; i++) - fpart /= 10; - } - whole += fpart; - *result = whole; - return 0; - } - } - - /* Invalid unit or character */ - errno = EINVAL; - return -1; -} - -/* Format the given "number" into human-readable form in "result". - * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. - * Return 0 on success, -1 and errno set if error. - */ -int -fmt_scaled(long long number, char *result) -{ - long long abval, fract = 0; - unsigned int i; - unit_type unit = NONE; - - abval = llabs(number); - - /* Not every negative long long has a positive representation. - * Also check for numbers that are just too darned big to format - */ - if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { - errno = ERANGE; - return -1; - } - - /* scale whole part; get unscaled fraction */ - for (i = 0; i < SCALE_LENGTH; i++) { - if (abval/1024 < scale_factors[i]) { - unit = units[i]; - fract = (i == 0) ? 0 : abval % scale_factors[i]; - number /= scale_factors[i]; - if (i > 0) - fract /= scale_factors[i - 1]; - break; - } - } - - fract = (10 * fract + 512) / 1024; - /* if the result would be >= 10, round main number */ - if (fract == 10) { - if (number >= 0) - number++; - else - number--; - fract = 0; - } - - if (number == 0) - strlcpy(result, "0B", FMT_SCALED_STRSIZE); - else if (unit == NONE || number >= 100 || number <= -100) { - if (fract >= 5) { - if (number >= 0) - number++; - else - number--; - } - (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", - number, scale_chars[unit]); - } else - (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", - number, fract, scale_chars[unit]); - - return 0; -} - -#ifdef MAIN -/* - * This is the original version of the program in the man page. - * Copy-and-paste whatever you need from it. - */ -int -main(int argc, char **argv) -{ - char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE]; - long long ninput = 10483892, result; - - if (scan_scaled(cinput, &result) == 0) - printf("\"%s\" -> %lld\n", cinput, result); - else - perror(cinput); - - if (fmt_scaled(ninput, buf) == 0) - printf("%lld -> \"%s\"\n", ninput, buf); - else - fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno)); - - return 0; -} -#endif diff --git a/lib/libutil/fparseln.3 b/lib/libutil/fparseln.3 @@ -1,144 +0,0 @@ -.\" $OpenBSD: fparseln.3,v 1.10 2015/09/14 15:14:55 schwarze Exp $ -.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $ -.\" -.\" Copyright (c) 1997 Christos Zoulas. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by Christos Zoulas. -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd $Mdocdate: September 14 2015 $ -.Dt FPARSELN 3 -.Os -.Sh NAME -.Nm fparseln -.Nd return the next logical line from a stream -.Sh SYNOPSIS -.In stdio.h -.In util.h -.Ft "char *" -.Fo fparseln -.Fa "FILE *stream" "size_t *len" "size_t *lineno" -.Fa "const char delim[3]" "int flags" -.Fc -.Sh DESCRIPTION -The -.Fn fparseln -function -returns a pointer to the next logical line from the stream referenced by -.Fa stream . -This string is null terminated, contains no trailing newline, -and is dynamically allocated on each invocation. -It is the responsibility of the caller to free the pointer. -.Pp -By default, if a character is escaped, both it and the preceding escape -character will be present in the returned string. -Various -.Fa flags -alter this behaviour. -.Pp -The meaning of the arguments is as follows: -.Bl -tag -width "lineno" -.It Fa stream -The stream to read from. -.It Fa len -If not -.Dv NULL , -the length of the string is stored in the memory location referenced by -.Fa len . -.It Fa lineno -If not -.Dv NULL , -the value of the memory location to which -.Fa lineno -references is incremented by the number of lines actually read from the file. -.It Fa delim -Contains the escape, continuation, and comment characters. -If a character is NUL then processing for that character is disabled. -If -.Dv NULL , -all characters default to values specified below. -The contents of -.Fa delim -is as follows: -.Bl -tag -width "delim[0]" -.It Fa delim[0] -The escape character, which defaults to -.Ql \e , -is used to remove any special meaning from the next character. -.It Fa delim[1] -The continuation character, which defaults to -.Ql \e , -is used to indicate that the next line should be concatenated with the -current one if this character is the last character on the current line -and is not escaped. -.It Fa delim[2] -The comment character, which defaults to -.Ql # , -if not escaped indicates the beginning of a comment that extends until the -end of the current line. -.El -.It Fa flags -If non-zero, alter the operation of -.Fn fparseln . -The various flags, which may be OR'ed together, are: -.Bl -tag -width "FPARSELN_UNESCCOMM" -.It Dv FPARSELN_UNESCCOMM -Remove escape preceding an escaped comment. -.It Dv FPARSELN_UNESCCONT -Remove escape preceding an escaped continuation. -.It Dv FPARSELN_UNESCESC -Remove escape preceding an escaped escape. -.It Dv FPARSELN_UNESCREST -Remove escape preceding any other character. -.It Dv FPARSELN_UNESCALL -All of the above. -.El -.El -.Sh RETURN VALUES -Upon successful completion a pointer to the parsed line is returned; -otherwise, -.Dv NULL -is returned. -.Pp -Internally, the -.Fn fparseln -function uses -.Xr fgetln 3 , -so all error conditions that apply to -.Xr fgetln 3 -apply to -.Fn fparseln -as well. -In addition -.Fn fparseln -may set -.Va errno -to -.Er ENOMEM -and return -.Dv NULL -if it runs out of memory. -.Sh SEE ALSO -.Xr fgetln 3 diff --git a/lib/libutil/fparseln.c b/lib/libutil/fparseln.c @@ -1,208 +0,0 @@ -/* $OpenBSD: fparseln.c,v 1.7 2012/12/05 23:20:06 deraadt Exp $ */ -/* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */ - -/* - * Copyright (c) 1997 Christos Zoulas. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christos Zoulas. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include "util.h" - -static int isescaped(const char *, const char *, int); - -/* isescaped(): - * Return true if the character in *p that belongs to a string - * that starts in *sp, is escaped by the escape character esc. - */ -static int -isescaped(const char *sp, const char *p, int esc) -{ - const char *cp; - size_t ne; - - /* No escape character */ - if (esc == '\0') - return 1; - - /* Count the number of escape characters that precede ours */ - for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) - continue; - - /* Return true if odd number of escape characters */ - return (ne & 1) != 0; -} - - -/* fparseln(): - * Read a line from a file parsing continuations ending in \ - * and eliminating trailing newlines, or comments starting with - * the comment char. - */ -char * -fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], - int flags) -{ - static const char dstr[3] = { '\\', '\\', '#' }; - char *buf = NULL, *ptr, *cp, esc, con, nl, com; - size_t s, len = 0; - int cnt = 1; - - if (str == NULL) - str = dstr; - - esc = str[0]; - con = str[1]; - com = str[2]; - - /* - * XXX: it would be cool to be able to specify the newline character, - * but unfortunately, fgetln does not let us - */ - nl = '\n'; - - while (cnt) { - cnt = 0; - - if (lineno) - (*lineno)++; - - if ((ptr = fgetln(fp, &s)) == NULL) - break; - - if (s && com) { /* Check and eliminate comments */ - for (cp = ptr; cp < ptr + s; cp++) - if (*cp == com && !isescaped(ptr, cp, esc)) { - s = cp - ptr; - cnt = s == 0 && buf == NULL; - break; - } - } - - if (s && nl) { /* Check and eliminate newlines */ - cp = &ptr[s - 1]; - - if (*cp == nl) - s--; /* forget newline */ - } - - if (s && con) { /* Check and eliminate continuations */ - cp = &ptr[s - 1]; - - if (*cp == con && !isescaped(ptr, cp, esc)) { - s--; /* forget escape */ - cnt = 1; - } - } - - if (s == 0 && buf != NULL) - continue; - - if ((cp = realloc(buf, len + s + 1)) == NULL) { - free(buf); - return NULL; - } - buf = cp; - - (void) memcpy(buf + len, ptr, s); - len += s; - buf[len] = '\0'; - } - - if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && - strchr(buf, esc) != NULL) { - ptr = cp = buf; - while (cp[0] != '\0') { - int skipesc; - - while (cp[0] != '\0' && cp[0] != esc) - *ptr++ = *cp++; - if (cp[0] == '\0' || cp[1] == '\0') - break; - - skipesc = 0; - if (cp[1] == com) - skipesc += (flags & FPARSELN_UNESCCOMM); - if (cp[1] == con) - skipesc += (flags & FPARSELN_UNESCCONT); - if (cp[1] == esc) - skipesc += (flags & FPARSELN_UNESCESC); - if (cp[1] != com && cp[1] != con && cp[1] != esc) - skipesc = (flags & FPARSELN_UNESCREST); - - if (skipesc) - cp++; - else - *ptr++ = *cp++; - *ptr++ = *cp++; - } - *ptr = '\0'; - len = strlen(buf); - } - - if (size) - *size = len; - return buf; -} - -#ifdef TEST - -int main(int, char **); - -int -main(argc, argv) - int argc; - char **argv; -{ - char *ptr; - size_t size, line; - - line = 0; - while ((ptr = fparseln(stdin, &size, &line, NULL, - FPARSELN_UNESCALL)) != NULL) - printf("line %d (%d) |%s|\n", line, size, ptr); - return 0; -} - -/* - -# This is a test -line 1 -line 2 \ -line 3 # Comment -line 4 \# Not comment \\\\ - -# And a comment \ -line 5 \\\ -line 6 - -*/ - -#endif /* TEST */ diff --git a/lib/libutil/imsg-buffer.c b/lib/libutil/imsg-buffer.c @@ -1,309 +0,0 @@ -/* $OpenBSD: imsg-buffer.c,v 1.8 2015/12/29 18:05:01 benno Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <limits.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "imsg.h" - -int ibuf_realloc(struct ibuf *, size_t); -void ibuf_enqueue(struct msgbuf *, struct ibuf *); -void ibuf_dequeue(struct msgbuf *, struct ibuf *); - -struct ibuf * -ibuf_open(size_t len) -{ - struct ibuf *buf; - - if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) - return (NULL); - if ((buf->buf = malloc(len)) == NULL) { - free(buf); - return (NULL); - } - buf->size = buf->max = len; - buf->fd = -1; - - return (buf); -} - -struct ibuf * -ibuf_dynamic(size_t len, size_t max) -{ - struct ibuf *buf; - - if (max < len) - return (NULL); - - if ((buf = ibuf_open(len)) == NULL) - return (NULL); - - if (max > 0) - buf->max = max; - - return (buf); -} - -int -ibuf_realloc(struct ibuf *buf, size_t len) -{ - u_char *b; - - /* on static buffers max is eq size and so the following fails */ - if (buf->wpos + len > buf->max) { - errno = ERANGE; - return (-1); - } - - b = realloc(buf->buf, buf->wpos + len); - if (b == NULL) - return (-1); - buf->buf = b; - buf->size = buf->wpos + len; - - return (0); -} - -int -ibuf_add(struct ibuf *buf, const void *data, size_t len) -{ - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (-1); - - memcpy(buf->buf + buf->wpos, data, len); - buf->wpos += len; - return (0); -} - -void * -ibuf_reserve(struct ibuf *buf, size_t len) -{ - void *b; - - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (NULL); - - b = buf->buf + buf->wpos; - buf->wpos += len; - return (b); -} - -void * -ibuf_seek(struct ibuf *buf, size_t pos, size_t len) -{ - /* only allowed to seek in already written parts */ - if (pos + len > buf->wpos) - return (NULL); - - return (buf->buf + pos); -} - -size_t -ibuf_size(struct ibuf *buf) -{ - return (buf->wpos); -} - -size_t -ibuf_left(struct ibuf *buf) -{ - return (buf->max - buf->wpos); -} - -void -ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) -{ - ibuf_enqueue(msgbuf, buf); -} - -int -ibuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - - memset(&iov, 0, sizeof(iov)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - } - -again: - if ((n = writev(msgbuf->fd, iov, i)) == -1) { - if (errno == EINTR) - goto again; - if (errno == ENOBUFS) - errno = EAGAIN; - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - - msgbuf_drain(msgbuf, n); - - return (1); -} - -void -ibuf_free(struct ibuf *buf) -{ - if (buf == NULL) - return; - free(buf->buf); - free(buf); -} - -void -msgbuf_init(struct msgbuf *msgbuf) -{ - msgbuf->queued = 0; - msgbuf->fd = -1; - TAILQ_INIT(&msgbuf->bufs); -} - -void -msgbuf_drain(struct msgbuf *msgbuf, size_t n) -{ - struct ibuf *buf, *next; - - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (buf->rpos + n >= buf->wpos) { - n -= buf->wpos - buf->rpos; - ibuf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } -} - -void -msgbuf_clear(struct msgbuf *msgbuf) -{ - struct ibuf *buf; - - while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) - ibuf_dequeue(msgbuf, buf); -} - -int -msgbuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int))]; - } cmsgbuf; - - memset(&iov, 0, sizeof(iov)); - memset(&msg, 0, sizeof(msg)); - memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - if (buf->fd != -1) - break; - } - - msg.msg_iov = iov; - msg.msg_iovlen = i; - - if (buf != NULL && buf->fd != -1) { - msg.msg_control = (caddr_t)&cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(cmsg) = buf->fd; - } - -again: - if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { - if (errno == EINTR) - goto again; - if (errno == ENOBUFS) - errno = EAGAIN; - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - - /* - * assumption: fd got sent if sendmsg sent anything - * this works because fds are passed one at a time - */ - if (buf != NULL && buf->fd != -1) { - close(buf->fd); - buf->fd = -1; - } - - msgbuf_drain(msgbuf, n); - - return (1); -} - -void -ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); - msgbuf->queued++; -} - -void -ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_REMOVE(&msgbuf->bufs, buf, entry); - - if (buf->fd != -1) - close(buf->fd); - - msgbuf->queued--; - ibuf_free(buf); -} diff --git a/lib/libutil/imsg.c b/lib/libutil/imsg.c @@ -1,302 +0,0 @@ -/* $OpenBSD: imsg.c,v 1.13 2015/12/09 11:54:12 tb Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "imsg.h" - -int imsg_fd_overhead = 0; - -int imsg_get_fd(struct imsgbuf *); - -void -imsg_init(struct imsgbuf *ibuf, int fd) -{ - msgbuf_init(&ibuf->w); - memset(&ibuf->r, 0, sizeof(ibuf->r)); - ibuf->fd = fd; - ibuf->w.fd = fd; - ibuf->pid = getpid(); - TAILQ_INIT(&ibuf->fds); -} - -ssize_t -imsg_read(struct imsgbuf *ibuf) -{ - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int) * 1)]; - } cmsgbuf; - struct iovec iov; - ssize_t n = -1; - int fd; - struct imsg_fd *ifd; - - memset(&msg, 0, sizeof(msg)); - memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - - iov.iov_base = ibuf->r.buf + ibuf->r.wpos; - iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - - if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) - return (-1); - -again: - if (getdtablecount() + imsg_fd_overhead + - (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) - >= getdtablesize()) { - errno = EAGAIN; - free(ifd); - return (-1); - } - - if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { - if (errno == EINTR) - goto again; - goto fail; - } - - ibuf->r.wpos += n; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - int i; - int j; - - /* - * We only accept one file descriptor. Due to C - * padding rules, our control buffer might contain - * more than one fd, and we must close them. - */ - j = ((char *)cmsg + cmsg->cmsg_len - - (char *)CMSG_DATA(cmsg)) / sizeof(int); - for (i = 0; i < j; i++) { - fd = ((int *)CMSG_DATA(cmsg))[i]; - if (ifd != NULL) { - ifd->fd = fd; - TAILQ_INSERT_TAIL(&ibuf->fds, ifd, - entry); - ifd = NULL; - } else - close(fd); - } - } - /* we do not handle other ctl data level */ - } - -fail: - free(ifd); - return (n); -} - -ssize_t -imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) -{ - size_t av, left, datalen; - - av = ibuf->r.wpos; - - if (IMSG_HEADER_SIZE > av) - return (0); - - memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); - if (imsg->hdr.len < IMSG_HEADER_SIZE || - imsg->hdr.len > MAX_IMSGSIZE) { - errno = ERANGE; - return (-1); - } - if (imsg->hdr.len > av) - return (0); - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; - if (datalen == 0) - imsg->data = NULL; - else if ((imsg->data = malloc(datalen)) == NULL) - return (-1); - - if (imsg->hdr.flags & IMSGF_HASFD) - imsg->fd = imsg_get_fd(ibuf); - else - imsg->fd = -1; - - memcpy(imsg->data, ibuf->r.rptr, datalen); - - if (imsg->hdr.len < av) { - left = av - imsg->hdr.len; - memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); - ibuf->r.wpos = left; - } else - ibuf->r.wpos = 0; - - return (datalen + IMSG_HEADER_SIZE); -} - -int -imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, const void *data, u_int16_t datalen) -{ - struct ibuf *wbuf; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - if (imsg_add(wbuf, data, datalen) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -int -imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, const struct iovec *iov, int iovcnt) -{ - struct ibuf *wbuf; - int i, datalen = 0; - - for (i = 0; i < iovcnt; i++) - datalen += iov[i].iov_len; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - for (i = 0; i < iovcnt; i++) - if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -/* ARGSUSED */ -struct ibuf * -imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, u_int16_t datalen) -{ - struct ibuf *wbuf; - struct imsg_hdr hdr; - - datalen += IMSG_HEADER_SIZE; - if (datalen > MAX_IMSGSIZE) { - errno = ERANGE; - return (NULL); - } - - hdr.type = type; - hdr.flags = 0; - hdr.peerid = peerid; - if ((hdr.pid = pid) == 0) - hdr.pid = ibuf->pid; - if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { - return (NULL); - } - if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) - return (NULL); - - return (wbuf); -} - -int -imsg_add(struct ibuf *msg, const void *data, u_int16_t datalen) -{ - if (datalen) - if (ibuf_add(msg, data, datalen) == -1) { - ibuf_free(msg); - return (-1); - } - return (datalen); -} - -void -imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) -{ - struct imsg_hdr *hdr; - - hdr = (struct imsg_hdr *)msg->buf; - - hdr->flags &= ~IMSGF_HASFD; - if (msg->fd != -1) - hdr->flags |= IMSGF_HASFD; - - hdr->len = (u_int16_t)msg->wpos; - - ibuf_close(&ibuf->w, msg); -} - -void -imsg_free(struct imsg *imsg) -{ - free(imsg->data); -} - -int -imsg_get_fd(struct imsgbuf *ibuf) -{ - int fd; - struct imsg_fd *ifd; - - if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) - return (-1); - - fd = ifd->fd; - TAILQ_REMOVE(&ibuf->fds, ifd, entry); - free(ifd); - - return (fd); -} - -int -imsg_flush(struct imsgbuf *ibuf) -{ - while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) <= 0) - return (-1); - return (0); -} - -void -imsg_clear(struct imsgbuf *ibuf) -{ - int fd; - - msgbuf_clear(&ibuf->w); - while ((fd = imsg_get_fd(ibuf)) != -1) - close(fd); -} diff --git a/lib/libutil/imsg.h b/lib/libutil/imsg.h @@ -1,112 +0,0 @@ -/* $OpenBSD: imsg.h,v 1.3 2013/12/26 17:32:33 eric Exp $ */ - -/* - * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> - * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> - * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _IMSG_H_ -#define _IMSG_H_ - -#define IBUF_READ_SIZE 65535 -#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) -#define MAX_IMSGSIZE 16384 - -struct ibuf { - TAILQ_ENTRY(ibuf) entry; - u_char *buf; - size_t size; - size_t max; - size_t wpos; - size_t rpos; - int fd; -}; - -struct msgbuf { - TAILQ_HEAD(, ibuf) bufs; - u_int32_t queued; - int fd; -}; - -struct ibuf_read { - u_char buf[IBUF_READ_SIZE]; - u_char *rptr; - size_t wpos; -}; - -struct imsg_fd { - TAILQ_ENTRY(imsg_fd) entry; - int fd; -}; - -struct imsgbuf { - TAILQ_HEAD(, imsg_fd) fds; - struct ibuf_read r; - struct msgbuf w; - int fd; - pid_t pid; -}; - -#define IMSGF_HASFD 1 - -struct imsg_hdr { - u_int32_t type; - u_int16_t len; - u_int16_t flags; - u_int32_t peerid; - u_int32_t pid; -}; - -struct imsg { - struct imsg_hdr hdr; - int fd; - void *data; -}; - - -/* buffer.c */ -struct ibuf *ibuf_open(size_t); -struct ibuf *ibuf_dynamic(size_t, size_t); -int ibuf_add(struct ibuf *, const void *, size_t); -void *ibuf_reserve(struct ibuf *, size_t); -void *ibuf_seek(struct ibuf *, size_t, size_t); -size_t ibuf_size(struct ibuf *); -size_t ibuf_left(struct ibuf *); -void ibuf_close(struct msgbuf *, struct ibuf *); -int ibuf_write(struct msgbuf *); -void ibuf_free(struct ibuf *); -void msgbuf_init(struct msgbuf *); -void msgbuf_clear(struct msgbuf *); -int msgbuf_write(struct msgbuf *); -void msgbuf_drain(struct msgbuf *, size_t); - -/* imsg.c */ -void imsg_init(struct imsgbuf *, int); -ssize_t imsg_read(struct imsgbuf *); -ssize_t imsg_get(struct imsgbuf *, struct imsg *); -int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, const void *, u_int16_t); -int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, const struct iovec *, int); -struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - u_int16_t); -int imsg_add(struct ibuf *, const void *, u_int16_t); -void imsg_close(struct imsgbuf *, struct ibuf *); -void imsg_free(struct imsg *); -int imsg_flush(struct imsgbuf *); -void imsg_clear(struct imsgbuf *); - -#endif diff --git a/lib/libutil/imsg_init.3 b/lib/libutil/imsg_init.3 @@ -1,550 +0,0 @@ -.\" $OpenBSD: imsg_init.3,v 1.15 2015/12/29 18:05:23 benno Exp $ -.\" -.\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER -.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: December 29 2015 $ -.Dt IMSG_INIT 3 -.Os -.Sh NAME -.Nm imsg_init , -.Nm imsg_read , -.Nm imsg_get , -.Nm imsg_compose , -.Nm imsg_composev , -.Nm imsg_create , -.Nm imsg_add , -.Nm imsg_close , -.Nm imsg_free , -.Nm imsg_flush , -.Nm imsg_clear , -.Nm ibuf_open , -.Nm ibuf_dynamic , -.Nm ibuf_add , -.Nm ibuf_reserve , -.Nm ibuf_seek , -.Nm ibuf_size , -.Nm ibuf_left , -.Nm ibuf_close , -.Nm ibuf_write , -.Nm ibuf_free , -.Nm msgbuf_init , -.Nm msgbuf_clear , -.Nm msgbuf_write , -.Nm msgbuf_drain -.Nd IPC messaging functions -.Sh SYNOPSIS -.In sys/types.h -.In sys/queue.h -.In sys/uio.h -.In imsg.h -.Ft void -.Fn imsg_init "struct imsgbuf *ibuf" "int fd" -.Ft ssize_t -.Fn imsg_read "struct imsgbuf *ibuf" -.Ft ssize_t -.Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg" -.Ft int -.Fn imsg_compose "struct imsgbuf *ibuf" "u_int32_t type" "uint32_t peerid" \ - "pid_t pid" "int fd" "const void *data" "u_int16_t datalen" -.Ft int -.Fn imsg_composev "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \ - "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt" -.Ft "struct ibuf *" -.Fn imsg_create "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \ - "pid_t pid" "u_int16_t datalen" -.Ft int -.Fn imsg_add "struct ibuf *buf" "const void *data" "u_int16_t datalen" -.Ft void -.Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg" -.Ft void -.Fn imsg_free "struct imsg *imsg" -.Ft int -.Fn imsg_flush "struct imsgbuf *ibuf" -.Ft void -.Fn imsg_clear "struct imsgbuf *ibuf" -.Ft "struct ibuf *" -.Fn ibuf_open "size_t len" -.Ft "struct ibuf *" -.Fn ibuf_dynamic "size_t len" "size_t max" -.Ft int -.Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len" -.Ft "void *" -.Fn ibuf_reserve "struct ibuf *buf" "size_t len" -.Ft "void *" -.Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len" -.Ft size_t -.Fn ibuf_size "struct ibuf *buf" -.Ft size_t -.Fn ibuf_left "struct ibuf *buf" -.Ft void -.Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf" -.Ft int -.Fn ibuf_write "struct msgbuf *msgbuf" -.Ft void -.Fn ibuf_free "struct ibuf *buf" -.Ft void -.Fn msgbuf_init "struct msgbuf *msgbuf" -.Ft void -.Fn msgbuf_clear "struct msgbuf *msgbuf" -.Ft int -.Fn msgbuf_write "struct msgbuf *msgbuf" -.Ft void -.Fn msgbuf_drain "struct msgbuf *msgbuf" "size_t n" -.Sh DESCRIPTION -The -.Nm imsg -functions provide a simple mechanism for communication between processes -using sockets. -Each transmitted message is guaranteed to be presented to the receiving program -whole. -They are commonly used in privilege separated processes, where processes with -different rights are required to cooperate. -.Pp -A program using these functions should be linked with -.Em -lutil . -.Pp -The basic -.Nm -structure is the -.Em imsgbuf , -which wraps a file descriptor and represents one side of a channel on which -messages are sent and received: -.Bd -literal -offset indent -struct imsgbuf { - TAILQ_HEAD(, imsg_fd) fds; - struct ibuf_read r; - struct msgbuf w; - int fd; - pid_t pid; -}; -.Ed -.Pp -.Fn imsg_init -is a routine which initializes -.Fa ibuf -as one side of a channel associated with -.Fa fd . -The file descriptor is used to send and receive messages, -but is not closed by any of the imsg functions. -An imsgbuf is initialized with the -.Em w -member as the output buffer queue, -.Em fd -with the file descriptor passed to -.Fn imsg_init -and the other members for internal use only. -.Pp -The -.Fn imsg_clear -function frees any data allocated as part of an imsgbuf. -.Pp -.Fn imsg_create , -.Fn imsg_add -and -.Fn imsg_close -are generic construction routines for messages that are to be sent using an -imsgbuf. -.Pp -.Fn imsg_create -creates a new message with header specified by -.Fa type , -.Fa peerid -and -.Fa pid . -A -.Fa pid -of zero uses the process ID returned by -.Xr getpid 2 -when -.Fa ibuf -was initialized. -In addition to this common imsg header, -.Fa datalen -bytes of space may be reserved for attaching to this imsg. -This space is populated using -.Fn imsg_add . -Additionally, the file descriptor -.Fa fd -may be passed over the socket to the other process. -If -.Fa fd -is given, it is closed in the sending program after the message is sent. -A value of \-1 indicates no file descriptor should be passed. -.Fn imsg_create -returns a pointer to a new message if it succeeds, NULL otherwise. -.Pp -.Fn imsg_add -appends to -.Fa imsg -.Fa len -bytes of ancillary data pointed to by -.Fa buf . -It returns -.Fa len -if it succeeds, \-1 otherwise. -.Pp -.Fn imsg_close -completes creation of -.Fa imsg -by adding it to -.Fa imsgbuf -output buffer. -.Pp -.Fn imsg_compose -is a routine which is used to quickly create and queue an imsg. -It takes the same parameters as the -.Fn imsg_create , -.Fn imsg_add -and -.Fn imsg_close -routines, -except that only one ancillary data buffer can be provided. -This routine returns 1 if it succeeds, \-1 otherwise. -.Pp -.Fn imsg_composev -is similar to -.Fn imsg_compose . -It takes the same parameters, except that the ancillary data buffer is specified -by -.Fa iovec . -.Pp -.Fn imsg_flush -is a function which calls -.Fn msgbuf_write -in a loop until all imsgs in the output buffer are sent. -It returns 0 if it succeeds, \-1 otherwise. -.Pp -The -.Fn imsg_read -routine reads pending data with -.Xr recvmsg 2 -and queues it as individual messages on -.Fa imsgbuf . -It returns the number of bytes read on success, or \-1 on error. -A return value of \-1 from -.Fn imsg_read -invalidates -.Fa imsgbuf , -and renders it suitable only for passing to -.Fn imsg_clear . -.Pp -.Fn imsg_get -fills in an individual imsg pending on -.Fa imsgbuf -into the structure pointed to by -.Fa imsg . -It returns the total size of the message, 0 if no messages are ready, or \-1 -for an error. -Received messages are returned as a -.Em struct imsg , -which must be freed by -.Fn imsg_free -when no longer required. -.Em struct imsg -has this form: -.Bd -literal -offset indent -struct imsg { - struct imsg_hdr hdr; - int fd; - void *data; -}; - -struct imsg_hdr { - u_int32_t type; - u_int16_t len; - u_int16_t flags; - u_int32_t peerid; - u_int32_t pid; -}; -.Ed -.Pp -The header members are: -.Bl -tag -width Ds -offset indent -.It type -A integer identifier, typically used to express the meaning of the message. -.It len -The total length of the imsg, including the header and any ancillary data -transmitted with the message (pointed to by the -.Em data -member of the message itself). -.It flags -Flags used internally by the imsg functions: should not be used by application -programs. -.It peerid, pid -32-bit values specified on message creation and free for any use by the -caller, normally used to identify the message sender. -.El -.Pp -In addition, -.Em struct imsg -has the following: -.Bl -tag -width Ds -offset indent -.It fd -The file descriptor specified when the message was created and passed using the -socket control message API, or \-1 if no file descriptor was sent. -.It data -A pointer to the ancillary data transmitted with the imsg. -.El -.Pp -The IMSG_HEADER_SIZE define is the size of the imsg message header, which -may be subtracted from the -.Fa len -member of -.Em struct imsg_hdr -to obtain the length of any additional data passed with the message. -.Pp -MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently -16384 bytes. -.Sh BUFFERS -The imsg API defines functions to manipulate buffers, used internally and during -construction of imsgs with -.Fn imsg_create . -A -.Em struct ibuf -is a single buffer and a -.Em struct msgbuf -a queue of output buffers for transmission: -.Bd -literal -offset indent -struct ibuf { - TAILQ_ENTRY(ibuf) entry; - u_char *buf; - size_t size; - size_t max; - size_t wpos; - size_t rpos; - int fd; -}; - -struct msgbuf { - TAILQ_HEAD(, ibuf) bufs; - u_int32_t queued; - int fd; -}; -.Ed -.Pp -The -.Fn ibuf_open -function allocates a fixed-length buffer. -The buffer may not be resized and may contain a maximum of -.Fa len -bytes. -On success -.Fn ibuf_open -returns a pointer to the buffer; on failure it returns NULL. -.Pp -.Fn ibuf_dynamic -allocates a resizeable buffer of initial length -.Fa len -and maximum size -.Fa max . -Buffers allocated with -.Fn ibuf_dynamic -are automatically grown if necessary when data is added. -.Pp -.Fn ibuf_add -is a routine which appends a block of data to -.Fa buf . -0 is returned on success and \-1 on failure. -.Pp -.Fn ibuf_reserve -is used to reserve -.Fa len -bytes in -.Fa buf . -A pointer to the start of the reserved space is returned, or NULL on error. -.Pp -.Fn ibuf_seek -is a function which returns a pointer to the part of the buffer at offset -.Fa pos -and of extent -.Fa len . -NULL is returned if the requested range is outside the part of the buffer -in use. -.Pp -.Fn ibuf_size -and -.Fn ibuf_left -are functions which return the total bytes used and available in -.Fa buf -respectively. -.Pp -.Fn ibuf_close -appends -.Fa buf -to -.Fa msgbuf -ready to be sent. -.Pp -The -.Fn ibuf_write -routine transmits as many pending buffers as possible from -.Fn msgbuf -using -.Xr writev 2 . -It returns 1 if it succeeds, \-1 on error and 0 when no buffers were -pending or an EOF condition on the socket is detected. -Temporary resource shortages are returned with errno -.Er EAGAIN -and require the application to retry again in the future. -.Pp -.Fn ibuf_free -frees -.Fa buf -and any associated storage. -If -.Fa buf -is a NULL pointer, no action occurs. -.Pp -The -.Fn msgbuf_init -function initializes -.Fa msgbuf -so that buffers may be appended to it. -The -.Em fd -member should also be set directly before -.Fn msgbuf_write -is used. -.Pp -.Fn msgbuf_clear -empties a msgbuf, removing and discarding any queued buffers. -.Pp -The -.Fn msgbuf_write -routine calls -.Xr sendmsg 2 -to transmit buffers queued in -.Fa msgbuf . -It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty -or an EOF condition on the socket is detected. -Temporary resource shortages are returned with errno -.Er EAGAIN -and require the application to retry again in the future. -.Pp -.Fn msgbuf_drain -discards data from buffers queued in -.Fa msgbuf -until -.Fa n -bytes have been removed or -.Fa msgbuf -is empty. -.Sh EXAMPLES -In a typical program, a channel between two processes is created with -.Xr socketpair 2 , -and an -.Em imsgbuf -created around one file descriptor in each process: -.Bd -literal -offset indent -struct imsgbuf parent_ibuf, child_ibuf; -int imsg_fds[2]; - -if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) - err(1, "socketpair"); - -switch (fork()) { -case -1: - err(1, "fork"); -case 0: - /* child */ - close(imsg_fds[0]); - imsg_init(&child_ibuf, imsg_fds[1]); - exit(child_main(&child_ibuf)); -} - -/* parent */ -close(imsg_fds[1]); -imsg_init(&parent_ibuf, imsg_fds[0]); -exit(parent_main(&parent_ibuf)); -.Ed -.Pp -Messages may then be composed and queued on the -.Em imsgbuf , -for example using the -.Fn imsg_compose -function: -.Bd -literal -offset indent -enum imsg_type { - IMSG_A_MESSAGE, - IMSG_MESSAGE2 -}; - -int -child_main(struct imsgbuf *ibuf) -{ - int idata; - ... - idata = 42; - imsg_compose(ibuf, IMSG_A_MESSAGE, - 0, 0, -1, &idata, sizeof idata); - ... -} -.Ed -.Pp -A mechanism such as -.Xr poll 2 -or the -.Xr event 3 -library is used to monitor the socket file descriptor. -When the socket is ready for writing, queued messages are transmitted with -.Fn msgbuf_write : -.Bd -literal -offset indent - if (msgbuf_write(&ibuf-\*(Gtw) \*(Lt= 0 && errno != EAGAIN) { - /* handle write failure */ - } -.Ed -.Pp -And when ready for reading, messages are first received using -.Fn imsg_read -and then extracted with -.Fn imsg_get : -.Bd -literal -offset indent -void -dispatch_imsg(struct imsgbuf *ibuf) -{ - struct imsg imsg; - ssize_t n, datalen; - int idata; - - if (((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) || n == 0) { - /* handle socket error */ - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) { - /* handle read error */ - } - if (n == 0) /* no more messages */ - return; - datalen = imsg.hdr.len - IMSG_HEADER_SIZE; - - switch (imsg.hdr.type) { - case IMSG_A_MESSAGE: - if (datalen \*(Lt sizeof idata) { - /* handle corrupt message */ - } - memcpy(&idata, imsg.data, sizeof idata); - /* handle message received */ - break; - ... - } - - imsg_free(&imsg); - } -} -.Ed -.Sh SEE ALSO -.Xr socketpair 2 , -.Xr unix 4 diff --git a/lib/libutil/isduid.3 b/lib/libutil/isduid.3 @@ -1,61 +0,0 @@ -.\" $OpenBSD: isduid.3,v 1.3 2015/07/15 15:16:59 sobrado Exp $ -.\" -.\" * Copyright (c) Joel Sing <jsing@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: July 15 2015 $ -.Dt ISDUID 3 -.Os -.Sh NAME -.Nm isduid -.Nd disklabel UID test -.Sh SYNOPSIS -.In util.h -.Ft int -.Fn isduid "char *duid" "int dflags" -.Sh DESCRIPTION -The -.Fn isduid -function tests the string -.Fa duid -to see if it is a valid -.Xr disklabel 8 -UID. -The -.Fa dflags -are specified using the same flags as used by -.Xr opendev 3 . -.Pp -If the OPENDEV_PART flag is included in -.Fa dflags -the disklabel UID must consist of a 16-character hexadecimal string. -Otherwise the disklabel UID must consist of a 16-character hexadecimal string -followed by a -.Sq \&. -and a partition letter. -.Sh RETURN VALUES -The -.Fn isduid -function returns non-zero if -.Fa duid -is a valid DUID, otherwise zero is returned. -.Sh SEE ALSO -.Xr opendev 3 , -.Xr disklabel 5 , -.Xr disklabel 8 -.Sh HISTORY -The -.Fn isduid -function first appeared in -.Ox 4.9 . diff --git a/lib/libutil/logwtmp.c b/lib/libutil/logwtmp.c @@ -1,65 +0,0 @@ -/* $OpenBSD: logwtmp.c,v 1.9 2005/08/02 21:46:23 espie Exp $ */ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/stat.h> - -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <utmp.h> - -#include "util.h" - -void -logwtmp(const char *line, const char *name, const char *host) -{ - struct stat buf; - struct utmp ut; - int fd; - - if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) - return; - if (fstat(fd, &buf) == 0) { - (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line)); - (void) strncpy(ut.ut_name, name, sizeof(ut.ut_name)); - (void) strncpy(ut.ut_host, host, sizeof(ut.ut_host)); -#ifdef __linux - (void) time((time_t *)&ut.ut_tv.tv_sec); -#else - (void) time(&ut.ut_time); -#endif - if (write(fd, &ut, sizeof(struct utmp)) != - sizeof(struct utmp)) - (void) ftruncate(fd, buf.st_size); - } - (void) close(fd); -} diff --git a/lib/libutil/ohash.c b/lib/libutil/ohash.c @@ -1,327 +0,0 @@ -/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ - -/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> -#include "ohash.h" - -struct _ohash_record { - uint32_t hv; - const char *p; -}; - -#define DELETED ((const char *)h) -#define NONE (h->size) - -/* Don't bother changing the hash table if the change is small enough. */ -#define MINSIZE (1UL << 4) -#define MINDELETED 4 - -static void ohash_resize(struct ohash *); - - -/* This handles the common case of variable length keys, where the - * key is stored at the end of the record. - */ -void * -ohash_create_entry(struct ohash_info *i, const char *start, const char **end) -{ - char *p; - - if (!*end) - *end = start + strlen(start); - p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); - if (p) { - memcpy(p+i->key_offset, start, *end-start); - p[i->key_offset + (*end - start)] = '\0'; - } - return (void *)p; -} - -/* hash_delete only frees the hash structure. Use hash_first/hash_next - * to free entries as well. */ -void -ohash_delete(struct ohash *h) -{ - (h->info.free)(h->t, h->info.data); -#ifndef NDEBUG - h->t = NULL; -#endif -} - -static void -ohash_resize(struct ohash *h) -{ - struct _ohash_record *n; - size_t ns; - unsigned int j; - unsigned int i, incr; - - if (4 * h->deleted < h->total) { - if (h->size >= (UINT_MAX >> 1U)) - ns = UINT_MAX; - else - ns = h->size << 1U; - } else if (3 * h->deleted > 2 * h->total) - ns = h->size >> 1U; - else - ns = h->size; - if (ns < MINSIZE) - ns = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_EXPAND++; - STAT_HASH_SIZE += ns - h->size; -#endif - - n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); - if (!n) - return; - - for (j = 0; j < h->size; j++) { - if (h->t[j].p != NULL && h->t[j].p != DELETED) { - i = h->t[j].hv % ns; - incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; - while (n[i].p != NULL) { - i += incr; - if (i >= ns) - i -= ns; - } - n[i].hv = h->t[j].hv; - n[i].p = h->t[j].p; - } - } - (h->info.free)(h->t, h->info.data); - h->t = n; - h->size = ns; - h->total -= h->deleted; - h->deleted = 0; -} - -void * -ohash_remove(struct ohash *h, unsigned int i) -{ - void *result = (void *)h->t[i].p; - - if (result == NULL || result == DELETED) - return NULL; - -#ifdef STATS_HASH - STAT_HASH_ENTRIES--; -#endif - h->t[i].p = DELETED; - h->deleted++; - if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) - ohash_resize(h); - return result; -} - -void * -ohash_find(struct ohash *h, unsigned int i) -{ - if (h->t[i].p == DELETED) - return NULL; - else - return (void *)h->t[i].p; -} - -void * -ohash_insert(struct ohash *h, unsigned int i, void *p) -{ -#ifdef STATS_HASH - STAT_HASH_ENTRIES++; -#endif - if (h->t[i].p == DELETED) { - h->deleted--; - h->t[i].p = p; - } else { - h->t[i].p = p; - /* Arbitrary resize boundary. Tweak if not efficient enough. */ - if (++h->total * 4 > h->size * 3) - ohash_resize(h); - } - return p; -} - -unsigned int -ohash_entries(struct ohash *h) -{ - return h->total - h->deleted; -} - -void * -ohash_first(struct ohash *h, unsigned int *pos) -{ - *pos = 0; - return ohash_next(h, pos); -} - -void * -ohash_next(struct ohash *h, unsigned int *pos) -{ - for (; *pos < h->size; (*pos)++) - if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) - return (void *)h->t[(*pos)++].p; - return NULL; -} - -void -ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) -{ - h->size = 1UL << size; - if (h->size < MINSIZE) - h->size = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_CREATION++; - STAT_HASH_SIZE += h->size; -#endif - /* Copy info so that caller may free it. */ - h->info.key_offset = info->key_offset; - h->info.calloc = info->calloc; - h->info.free = info->free; - h->info.alloc = info->alloc; - h->info.data = info->data; - h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), - h->info.data); - h->total = h->deleted = 0; -} - -uint32_t -ohash_interval(const char *s, const char **e) -{ - uint32_t k; - - if (!*e) - *e = s + strlen(s); - if (s == *e) - k = 0; - else - k = *s++; - while (s != *e) - k = ((k << 2) | (k >> 30)) ^ *s++; - return k; -} - -unsigned int -ohash_lookup_interval(struct ohash *h, const char *start, const char *end, - uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - strncmp(h->t[i].p+h->info.key_offset, start, - end - start) == 0 && - (h->t[i].p+h->info.key_offset)[end-start] == '\0') { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - return i; - } - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} - -unsigned int -ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - } return i; - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} - -unsigned int -ohash_qlookup(struct ohash *h, const char *s) -{ - const char *e = NULL; - return ohash_qlookupi(h, s, &e); -} - -unsigned int -ohash_qlookupi(struct ohash *h, const char *s, const char **e) -{ - uint32_t hv; - - hv = ohash_interval(s, e); - return ohash_lookup_interval(h, s, *e, hv); -} diff --git a/lib/libutil/ohash.h b/lib/libutil/ohash.h @@ -1,74 +0,0 @@ -/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ - -/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef OHASH_H -#define OHASH_H - -/* Open hashing support. - * Open hashing was chosen because it is much lighter than other hash - * techniques, and more efficient in most cases. - */ - -/* user-visible data structure */ -struct ohash_info { - ptrdiff_t key_offset; - void *data; /* user data */ - void *(*calloc)(size_t, size_t, void *); - void (*free)(void *, void *); - void *(*alloc)(size_t, void *); -}; - -struct _ohash_record; - -/* private structure. It's there just so you can do a sizeof */ -struct ohash { - struct _ohash_record *t; - struct ohash_info info; - unsigned int size; - unsigned int total; - unsigned int deleted; -}; - -/* For this to be tweakable, we use small primitives, and leave part of the - * logic to the client application. e.g., hashing is left to the client - * application. We also provide a simple table entry lookup that yields - * a hashing table index (opaque) to be used in find/insert/remove. - * The keys are stored at a known position in the client data. - */ -__BEGIN_DECLS -void ohash_init(struct ohash *, unsigned, struct ohash_info *); -void ohash_delete(struct ohash *); - -unsigned int ohash_lookup_interval(struct ohash *, const char *, - const char *, uint32_t); -unsigned int ohash_lookup_memory(struct ohash *, const char *, - size_t, uint32_t) - __attribute__ ((__bounded__(__string__,2,3))); -void *ohash_find(struct ohash *, unsigned int); -void *ohash_remove(struct ohash *, unsigned int); -void *ohash_insert(struct ohash *, unsigned int, void *); -void *ohash_first(struct ohash *, unsigned int *); -void *ohash_next(struct ohash *, unsigned int *); -unsigned int ohash_entries(struct ohash *); - -void *ohash_create_entry(struct ohash_info *, const char *, const char **); -uint32_t ohash_interval(const char *, const char **); - -unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); -unsigned int ohash_qlookup(struct ohash *, const char *); -__END_DECLS -#endif diff --git a/lib/libutil/ohash_init.3 b/lib/libutil/ohash_init.3 @@ -1,271 +0,0 @@ -.\" $OpenBSD: ohash_init.3,v 1.2 2014/05/13 14:01:41 jmc Exp $ -.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: May 13 2014 $ -.Dt OHASH_INIT 3 -.Os -.Sh NAME -.Nm ohash_init , -.Nm ohash_delete , -.Nm ohash_lookup_interval , -.Nm ohash_lookup_memory , -.Nm ohash_find , -.Nm ohash_remove , -.Nm ohash_insert , -.Nm ohash_first , -.Nm ohash_next , -.Nm ohash_entries -.Nd light-weight open hashing -.Sh SYNOPSIS -.In stdint.h -.In stddef.h -.In ohash.h -.Ft void -.Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info" -.Ft void -.Fn ohash_delete "struct ohash *h" -.Ft "unsigned int" -.Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv" -.Ft "unsigned int" -.Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv" -.Ft void * -.Fn ohash_find "struct ohash *h" "unsigned int i" -.Ft void * -.Fn ohash_remove "struct ohash *h" "unsigned int i" -.Ft void * -.Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p" -.Ft void * -.Fn ohash_first "struct ohash *h" "unsigned int *i" -.Ft void * -.Fn ohash_next "struct ohash *h" "unsigned int *i" -.Ft "unsigned int" -.Fn ohash_entries "struct ohash *h" -.Sh DESCRIPTION -These functions have been designed as a fast, extensible alternative to -the usual hash table functions. -They provide storage and retrieval of records indexed by keys, -where a key is a contiguous sequence of bytes at a fixed position in -each record. -Keys can either be NUL-terminated strings or fixed-size memory areas. -All functions take a pointer to an ohash structure as the -.Fa h -function argument. -Storage for this structure should be provided by user code. -.Pp -.Fn ohash_init -initializes the table to store roughly 2 to the power -.Fa size -elements. -.Fa info -is a pointer to a -.Fa struct ohash_info . -.Bd -literal -offset indent -struct ohash_info { - ptrdiff_t key_offset; - void *data; /* user data */ - void *(*calloc)(size_t, size_t, void *); - void (*free)(void *, void *); - void *(*alloc)(size_t, void *); -}; -.Ed -.Pp -The -.Va offset -field holds the position of the key in each record; -the -.Va calloc -and -.Va free -fields are pointers to -.Xr calloc 3 -and -.Xr free 3 Ns -like -functions, used for managing the table internal storage; -the -.Va alloc -field is only used by the utility function -.Xr ohash_create_entry 3 . -.Pp -Each of these functions are called similarly to their standard counterpart, -but with an extra -.Ft void * -parameter corresponding to the content of the field -.Fa data , -which can be used to communicate specific information to the functions. -.Pp -.Fn ohash_init -stores a copy of those fields internally, so -.Fa info -can be reclaimed after initialization. -.Pp -.Fn ohash_delete -frees storage internal to -.Fa h . -Elements themselves should be freed by the user first, using for instance -.Fn ohash_first -and -.Fn ohash_next . -.Pp -.Fn ohash_lookup_interval -and -.Fn ohash_lookup_memory -are the basic look-up element functions. -The hashing function result is provided by the user as -.Fa hv . -These return a -.Qq slot -in the ohash table -.Fa h , -to be used with -.Fn ohash_find , -.Fn ohash_insert , -or -.Fn ohash_remove . -This slot is only valid up to the next call to -.Fn ohash_insert -or -.Fn ohash_remove . -.Pp -.Fn ohash_lookup_interval -handles string-like keys. -.Fn ohash_lookup_interval -assumes the key is the interval between -.Fa start -and -.Fa end , -exclusive, -though the actual elements stored in the table should only contain -NUL-terminated keys. -.Pp -.Fn ohash_lookup_memory -assumes the key is the memory area starting at -.Fa k -of size -.Fa s . -All bytes are significant in key comparison. -.Pp -.Fn ohash_find -retrieves an element from a slot -.Fa i -returned by the -.Fn ohash_lookup* -functions. -It returns -.Dv NULL -if the slot is empty. -.Pp -.Fn ohash_insert -inserts a new element -.Fa p -at slot -.Fa i . -Slot -.Fa i -must be empty and element -.Fa p -must have a key corresponding to the -.Fn ohash_lookup* -call. -.Pp -.Fn ohash_remove -removes the element at slot -.Fa i . -It returns the removed element, for user code to dispose of, or -.Dv NULL -if the slot was empty. -.Pp -.Fn ohash_first -and -.Fn ohash_next -can be used to access all elements in an ohash table, like this: -.Bd -literal -offset indent -for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i)) - do_something_with(n); -.Ed -.Pp -.Fa i -points to an auxiliary unsigned integer used to record the current position -in the ohash table. -Those functions are safe to use even while entries are added to/removed -from the table, but in such a case they don't guarantee that new entries -will be returned. -As a special case, they can safely be used to free elements in the table. -.Pp -.Fn ohash_entries -returns the number of elements in the hash table. -.Sh STORAGE HANDLING -Only -.Fn ohash_init , -.Fn ohash_insert , -.Fn ohash_remove -and -.Fn ohash_delete -may call the user-supplied memory functions: -.Bd -literal -offset indent -p = (*info->calloc)(n, sizeof_record, info->data); -/* copy data from old to p */ -(*info->free)(old, info->data); -.Ed -.Pp -It is the responsibility of the user memory allocation code to verify -that those calls did not fail. -.Pp -If memory allocation fails, -.Fn ohash_init -returns a useless hash table. -.Fn ohash_insert -and -.Fn ohash_remove -still perform the requested operation, but the returned table should be -considered read-only. -It can still be accessed by -.Fn ohash_lookup* , -.Fn ohash_find , -.Fn ohash_first -and -.Fn ohash_next -to dump relevant information to disk before aborting. -.Sh THREAD SAFETY -The open hashing functions are not thread-safe by design. -In particular, in a threaded environment, there is no guarantee that a -.Qq slot -will not move between a -.Fn ohash_lookup* -and a -.Fn ohash_find , -.Fn ohash_insert -or -.Fn ohash_remove -call. -.Pp -Multi-threaded applications should explicitly protect ohash table access. -.Sh SEE ALSO -.Xr hcreate 3 , -.Xr ohash_interval 3 -.Rs -.%A Donald E. Knuth -.%B The Art of Computer Programming -.%V Vol. 3 -.%P pp 506-550 -.%D 1973 -.Re -.Sh STANDARDS -Those functions are completely non-standard and should be avoided in -portable programs. -.Sh HISTORY -Those functions were designed and written for -.Ox -.Xr make 1 -by Marc Espie in 1999. diff --git a/lib/libutil/ohash_interval.3 b/lib/libutil/ohash_interval.3 @@ -1,93 +0,0 @@ -.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $ -.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: May 12 2014 $ -.Dt OHASH_INTERVAL 3 -.Os -.Sh NAME -.Nm ohash_interval , -.Nm ohash_create_entry , -.Nm ohash_qlookup , -.Nm ohash_qlookupi -.Nd helper functions for open hashing -.Sh SYNOPSIS -.In stdint.h -.In stddef.h -.In ohash.h -.Ft uint32_t -.Fn ohash_interval "const char *start" "const char **pend" -.Ft "void *" -.Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend" -.Ft "unsigned int" -.Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend" -.Ft "unsigned int" -.Fn ohash_qlookup "struct ohash *h" "const char *start" -.Sh DESCRIPTION -These functions are commonly used to simplify open hashing usage, and use -similar conventions. -They operate indifferently on NUL-terminated strings -.Po -by setting -.Fa *pend -= -.Dv NULL -.Pc -or memory ranges -.Po -delimited by -.Fa start -and -.Fa *pend -.Pc . -For NUL-terminated strings, as a side effect, those functions -set -.Fa *pend -to the terminating NUL byte. -.Pp -.Fn ohash_interval -is a simple hashing function that yields good results on common data sets. -.Pp -.Fn ohash_create_entry -can be used to create a new record with a given key. -In that case, -the alloc field of -.Fa info -should point to a -.Xr malloc 3 Ns -like -function to allocate the storage: -.Bd -literal -offset indent -p = (*info->alloc)(sz, info->data); -.Ed -.Pp -.Fn ohash_qlookupi -is a wrapper function that simply calls -.Fn ohash_interval -and -.Fn ohash_lookup_interval . -.Pp -.Fn ohash_qlookup -is a variation on -.Fn ohash_qlookupi -designed for NUL-terminated strings. -.Sh SEE ALSO -.Xr ohash_init 3 -.Sh STANDARDS -Those functions are completely non-standard and should be avoided in -portable programs. -.Sh HISTORY -Those functions were designed and written for -.Ox -.Xr make 1 -by Marc Espie in 1999. diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3 @@ -1,82 +0,0 @@ -.\" $OpenBSD: pidfile.3,v 1.7 2013/06/05 03:40:26 tedu Exp $ -.\" $NetBSD: pidfile.3,v 1.2 2001/04/12 22:34:31 sommerfeld Exp $ -.\" -.\" Copyright (c) 1999 The NetBSD Foundation, Inc. -.\" All rights reserved. -.\" -.\" This code is derived from software contributed to The NetBSD Foundation -.\" by Jason R. Thorpe. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS -.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd $Mdocdate: June 5 2013 $ -.Dt PIDFILE 3 -.Os -.Sh NAME -.Nm pidfile -.Nd write a daemon pid file -.Sh SYNOPSIS -.In util.h -.Ft int -.Fn pidfile "const char *basename" -.Sh DESCRIPTION -.Fn pidfile -writes a file containing the process ID of the program to the -.Pa /var/run -directory. -The file name has the form -.Pa /var/run/basename.pid . -If the -.Ar basename -argument is NULL, -.Nm -will determine the program name and use that instead. -.Pp -The pid file can be used as a quick reference if -the process needs to be sent a signal. -When the program exits, the pid file will be removed automatically, -unless the program receives a fatal signal. -.Sh RETURN VALUES -.Fn pidfile -returns 0 on success and -1 on failure. -.Sh SEE ALSO -.Xr atexit 3 -.Sh HISTORY -The -.Nm -function call appeared in -.Ox 3.0 . -.Sh CAVEATS -If -.Fn pidfile -is called multiple times with different -.Ar basename , -only the last pidfile will be removed upon exit. -.Pp -.Fn pidfile -uses -.Fn atexit -to ensure the pidfile is unlinked at program exit. -However, programs that use the -.Fn _exit -function (for example, in signal handlers) -will not trigger this behaviour. diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c @@ -1,105 +0,0 @@ -/* $OpenBSD: pidfile.c,v 1.12 2015/11/27 01:57:59 mmcc Exp $ */ -/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ - -/*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <errno.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <util.h> - -static char *pidfile_path; -static pid_t pidfile_pid; - -static void pidfile_cleanup(void); - -extern char *__progname; - -int -pidfile(const char *basename) -{ - int save_errno; - pid_t pid; - FILE *f; - - if (basename == NULL) - basename = __progname; - - free(pidfile_path); - pidfile_path = NULL; - - /* _PATH_VARRUN includes trailing / */ - if (asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename) == -1) - return (-1); - - if ((f = fopen(pidfile_path, "w")) == NULL) { - save_errno = errno; - free(pidfile_path); - pidfile_path = NULL; - errno = save_errno; - return (-1); - } - - pid = getpid(); - if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) { - save_errno = errno; - (void) fclose(f); - (void) unlink(pidfile_path); - free(pidfile_path); - pidfile_path = NULL; - errno = save_errno; - return (-1); - } - (void) fclose(f); - - pidfile_pid = pid; - if (atexit(pidfile_cleanup) < 0) { - save_errno = errno; - (void) unlink(pidfile_path); - free(pidfile_path); - pidfile_path = NULL; - pidfile_pid = 0; - errno = save_errno; - return (-1); - } - - return (0); -} - -static void -pidfile_cleanup(void) -{ - - if (pidfile_path != NULL && pidfile_pid == getpid()) - (void) unlink(pidfile_path); -} diff --git a/lib/libutil/pkcs5_pbkdf2.3 b/lib/libutil/pkcs5_pbkdf2.3 @@ -1,63 +0,0 @@ -.\" $OpenBSD: pkcs5_pbkdf2.3,v 1.5 2013/06/05 03:40:26 tedu Exp $ -.\" -.\" Copyright (c) 2012 Ted Unangst <tedu@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: June 5 2013 $ -.Dt PKCS5_PBKDF2 3 -.Os -.Sh NAME -.Nm pkcs5_pbkdf2 -.Nd password-based key derivation function -.Sh SYNOPSIS -.In util.h -.Ft int -.Fn pkcs5_pbkdf2 "const char *pass" "size_t pass_len" "const char *salt" \ - "size_t salt_len" "u_int8_t *key" "size_t key_len" "u_int rounds" -.Sh DESCRIPTION -The -.Nm -function converts a password into a byte array suitable for use as -an encryption key. -The password and salt values are combined and repeatedly hashed -.Ar rounds -times. -The salt value should be randomly generated beforehand. -The repeated hashing is designed to thwart discovery of the key via -password guessing attacks. -The higher the number of rounds, the slower each attempt will be. -A minimum value of at least 1000 is recommended. -.Sh RETURN VALUES -The -.Fn pkcs5_pbkdf2 -function returns 0 to indicate success and -1 for failure. -.\" .Sh EXAMPLES -.\" .Sh ERRORS -.Sh SEE ALSO -.Xr sha1 1 , -.Xr bcrypt_pbkdf 3 -.Sh STANDARDS -.Rs -.%A B. Kaliski -.%D September 2000 -.%R RFC 2898 -.%T PKCS #5: Password-Based Cryptography Specification Version 2.0 -.Re -.\" .Sh HISTORY -.\" .Sh AUTHORS -.Sh CAVEATS -The standard allows for different hash functions to be used. -This implementation only uses -.Xr sha1 1 . -.\" .Sh BUGS diff --git a/lib/libutil/pkcs5_pbkdf2.c b/lib/libutil/pkcs5_pbkdf2.c @@ -1,122 +0,0 @@ -/* $OpenBSD: pkcs5_pbkdf2.c,v 1.9 2015/02/05 12:59:57 millert Exp $ */ - -/*- - * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> - -#include <string.h> -#include <stdint.h> -#include <stdlib.h> -#include <util.h> - -#include <sha1.h> - -#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) - -/* - * HMAC-SHA-1 (from RFC 2202). - */ -static void -hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key, - size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH]) -{ - SHA1_CTX ctx; - u_int8_t k_pad[SHA1_BLOCK_LENGTH]; - u_int8_t tk[SHA1_DIGEST_LENGTH]; - int i; - - if (key_len > SHA1_BLOCK_LENGTH) { - SHA1Init(&ctx); - SHA1Update(&ctx, key, key_len); - SHA1Final(tk, &ctx); - - key = tk; - key_len = SHA1_DIGEST_LENGTH; - } - - bzero(k_pad, sizeof k_pad); - bcopy(key, k_pad, key_len); - for (i = 0; i < SHA1_BLOCK_LENGTH; i++) - k_pad[i] ^= 0x36; - - SHA1Init(&ctx); - SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); - SHA1Update(&ctx, text, text_len); - SHA1Final(digest, &ctx); - - bzero(k_pad, sizeof k_pad); - bcopy(key, k_pad, key_len); - for (i = 0; i < SHA1_BLOCK_LENGTH; i++) - k_pad[i] ^= 0x5c; - - SHA1Init(&ctx); - SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH); - SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH); - SHA1Final(digest, &ctx); -} - -/* - * Password-Based Key Derivation Function 2 (PKCS #5 v2.0). - * Code based on IEEE Std 802.11-2007, Annex H.4.2. - */ -int -pkcs5_pbkdf2(const char *pass, size_t pass_len, const uint8_t *salt, - size_t salt_len, uint8_t *key, size_t key_len, unsigned int rounds) -{ - uint8_t *asalt, obuf[SHA1_DIGEST_LENGTH]; - uint8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH]; - unsigned int i, j; - unsigned int count; - size_t r; - - if (rounds < 1 || key_len == 0) - return -1; - if (salt_len == 0 || salt_len > SIZE_MAX - 4) - return -1; - if ((asalt = malloc(salt_len + 4)) == NULL) - return -1; - - memcpy(asalt, salt, salt_len); - - for (count = 1; key_len > 0; count++) { - asalt[salt_len + 0] = (count >> 24) & 0xff; - asalt[salt_len + 1] = (count >> 16) & 0xff; - asalt[salt_len + 2] = (count >> 8) & 0xff; - asalt[salt_len + 3] = count & 0xff; - hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1); - memcpy(obuf, d1, sizeof(obuf)); - - for (i = 1; i < rounds; i++) { - hmac_sha1(d1, sizeof(d1), pass, pass_len, d2); - memcpy(d1, d2, sizeof(d1)); - for (j = 0; j < sizeof(obuf); j++) - obuf[j] ^= d1[j]; - } - - r = MINIMUM(key_len, SHA1_DIGEST_LENGTH); - memcpy(key, obuf, r); - key += r; - key_len -= r; - }; - explicit_bzero(asalt, salt_len + 4); - free(asalt); - explicit_bzero(d1, sizeof(d1)); - explicit_bzero(d2, sizeof(d2)); - explicit_bzero(obuf, sizeof(obuf)); - - return 0; -} diff --git a/lib/libutil/readlabel.c b/lib/libutil/readlabel.c @@ -1,144 +0,0 @@ -/* $OpenBSD: readlabel.c,v 1.13 2015/01/16 16:48:52 deraadt Exp $ */ - -/* - * Copyright (c) 1996, Jason Downs. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <sys/disk.h> -#include <sys/dkio.h> -#define DKTYPENAMES -#include <sys/disklabel.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <stdio.h> -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <fcntl.h> -#include <paths.h> -#include <string.h> -#include <unistd.h> - -#include "util.h" - -/* - * Try to get a disklabel for the specified device, and return mount_xxx - * style filesystem type name for the specified partition. - */ -char * -readlabelfs(char *device, int verbose) -{ - char rpath[PATH_MAX]; - struct dk_diskmap dm; - struct disklabel dk; - char part, *type; - struct stat sbuf; - int fd = -1; - - /* Perform disk mapping if device is given as a DUID. */ - if (isduid(device, 0)) { - if ((fd = open("/dev/diskmap", O_RDONLY)) != -1) { - bzero(&dm, sizeof(struct dk_diskmap)); - strlcpy(rpath, device, sizeof(rpath)); - part = rpath[strlen(rpath) - 1]; - dm.device = rpath; - dm.fd = fd; - dm.flags = DM_OPENPART; - if (ioctl(fd, DIOCMAP, &dm) == -1) - close(fd); - else - goto disklabel; - } - } - - /* Assuming device is of the form /dev/??p, build a raw partition. */ - if (stat(device, &sbuf) < 0) { - if (verbose) - warn("%s", device); - return (NULL); - } - switch (sbuf.st_mode & S_IFMT) { - case S_IFCHR: - /* Ok... already a raw device. Hmm. */ - strlcpy(rpath, device, sizeof(rpath)); - - /* Change partition name. */ - part = rpath[strlen(rpath) - 1]; - rpath[strlen(rpath) - 1] = 'a' + getrawpartition(); - break; - case S_IFBLK: - if (strlen(device) > sizeof(_PATH_DEV) - 1) { - snprintf(rpath, sizeof(rpath), "%sr%s", _PATH_DEV, - &device[sizeof(_PATH_DEV) - 1]); - /* Change partition name. */ - part = rpath[strlen(rpath) - 1]; - rpath[strlen(rpath) - 1] = 'a' + getrawpartition(); - break; - } - /* FALLTHROUGH */ - default: - if (verbose) - warnx("%s: not a device node", device); - return (NULL); - } - - /* If rpath doesn't exist, change that partition back. */ - fd = open(rpath, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) { - rpath[strlen(rpath) - 1] = part; - - fd = open(rpath, O_RDONLY); - if (fd < 0) { - if (verbose) - warn("%s", rpath); - return (NULL); - } - } else { - if (verbose) - warn("%s", rpath); - return (NULL); - } - } - -disklabel: - - if (ioctl(fd, DIOCGDINFO, &dk) < 0) { - if (verbose) - warn("%s: couldn't read disklabel", rpath); - close(fd); - return (NULL); - } - close(fd); - - if (dk.d_partitions[part - 'a'].p_fstype >= FSMAXTYPES) { - if (verbose) - warnx("%s: bad filesystem type in label", rpath); - return (NULL); - } - - type = fstypesnames[dk.d_partitions[part - 'a'].p_fstype]; - return ((type[0] == '\0') ? NULL : type); -} diff --git a/lib/libutil/readlabelfs.3 b/lib/libutil/readlabelfs.3 @@ -1,61 +0,0 @@ -.\" $OpenBSD: readlabelfs.3,v 1.8 2013/06/05 03:40:26 tedu Exp $ -.\" -.\" Copyright (c) 1996, Jason Downs. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS -.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, -.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.Dd $Mdocdate: June 5 2013 $ -.Dt READLABELFS 3 -.Os -.Sh NAME -.Nm readlabelfs -.Nd read disklabel filesystem type -.Sh SYNOPSIS -.In util.h -.Ft char * -.Fn readlabelfs "char *device" "int verbose" -.Sh DESCRIPTION -The -.Fn readlabelfs -function attempts to determine the filesystem type of the disk -partition specified by -.Fa device -and returns it in a short form that can be easily used to construct -arguments within -.Xr mount 8 -and similar high-level filesystem utilities. -.Pp -If the -.Fa verbose -argument is not 0, -.Fn readlabelfs -will print appropriate error messages before returning. -Otherwise, it produces no output on the terminal. -.Sh RETURN VALUES -.Fn readlabelfs -returns -.Dv NULL -upon error, or a valid filesystem type upon success. -.Sh HISTORY -.Fn readlabelfs -first appeared in -.Ox 2.0 . diff --git a/lib/libutil/shlib_version b/lib/libutil/shlib_version @@ -1,2 +0,0 @@ -major=12 -minor=1 diff --git a/lib/libutil/util.h b/lib/libutil/util.h @@ -1,91 +0,0 @@ -/* $OpenBSD: util.h,v 1.34 2013/06/03 21:07:02 tedu Exp $ */ -/* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */ - -/*- - * Copyright (c) 1995 - * The Regents of the University of California. All rights reserved. - * Portions Copyright (c) 1996, Jason Downs. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _UTIL_H_ -#define _UTIL_H_ - -#include <sys/types.h> -#include <stdio.h> - -/* - * fparseln() specific operation flags. - */ -#define FPARSELN_UNESCESC 0x01 -#define FPARSELN_UNESCCONT 0x02 -#define FPARSELN_UNESCCOMM 0x04 -#define FPARSELN_UNESCREST 0x08 -#define FPARSELN_UNESCALL 0x0f - -/* - * uucplock(3) specific flags. - */ -#define UU_LOCK_INUSE (1) -#define UU_LOCK_OK (0) -#define UU_LOCK_OPEN_ERR (-1) -#define UU_LOCK_READ_ERR (-2) -#define UU_LOCK_CREAT_ERR (-3) -#define UU_LOCK_WRITE_ERR (-4) -#define UU_LOCK_LINK_ERR (-5) -#define UU_LOCK_TRY_ERR (-6) -#define UU_LOCK_OWNER_ERR (-7) - -/* - * fmt_scaled(3) specific flags. - */ -#define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ - -/* - * stub struct definitions. - */ -struct termios; -struct utmp; -struct winsize; - -__BEGIN_DECLS -char *fparseln(FILE *, size_t *, size_t *, const char[3], int); -void logwtmp(const char *, const char *, const char *); -int pidfile(const char *); -const char *uu_lockerr(int); -int uu_lock(const char *); -int uu_lock_txfr(const char *, pid_t); -int uu_unlock(const char *); -int fmt_scaled(long long, char *); -int scan_scaled(char *, long long *); -int pkcs5_pbkdf2(const char *, size_t, const uint8_t *, size_t, - uint8_t *, size_t, unsigned int); -int bcrypt_pbkdf(const char *, size_t, const uint8_t *, size_t, - uint8_t *, size_t, unsigned int); - -__END_DECLS - -#endif /* !_UTIL_H_ */ diff --git a/lib/libutil/uucplock.3 b/lib/libutil/uucplock.3 @@ -1,178 +0,0 @@ -.\" $OpenBSD: uucplock.3,v 1.19 2015/11/10 23:48:18 jmc Exp $ -.\" -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" " -.Dd $Mdocdate: November 10 2015 $ -.Dt UU_LOCK 3 -.Os -.Sh NAME -.Nm uu_lock , -.Nm uu_unlock , -.Nm uu_lockerr , -.Nm uu_lock_txfr -.Nd acquire and release control of a serial device -.Sh SYNOPSIS -.In sys/types.h -.In util.h -.Ft int -.Fn uu_lock "const char *ttyname" -.Ft int -.Fn uu_lock_txfr "const char *ttyname" "pid_t pid" -.Ft int -.Fn uu_unlock "const char *ttyname" -.Ft const char * -.Fn uu_lockerr "int uu_lockresult" -.Sh DESCRIPTION -The -.Fn uu_lock -function attempts to create a lock file called -.Pa /var/spool/lock/LCK.. -with a suffix given by the passed -.Fa ttyname . -If the file already exists, it is expected to contain the process -ID of the locking program. -.Pp -If the file does not already exist, or the owning process given by -the process ID found in the lock file is no longer running, -.Fn uu_lock -will write its own process ID into the file and return success. -.Pp -.Fn uu_lock_txfr -transfers lock ownership to another process. -.Fn uu_lock -must have previously been successful. -.Pp -.Fn uu_unlock -removes the lockfile created by -.Fn uu_lock -for the given -.Fa ttyname . -Care should be taken that -.Fn uu_lock -was successful before calling -.Fn uu_unlock . -.Pp -.Fn uu_lockerr -returns an error string representing the error -.Fa uu_lockresult , -as returned from -.Fn uu_lock . -.Sh RETURN VALUES -.Fn uu_unlock -returns 0 on success and \-1 on failure. -.Pp -.Fn uu_lock -may return any of the following values: -.Pp -.Dv UU_LOCK_INUSE : -The lock is in use by another process. -.Pp -.Dv UU_LOCK_OK : -The lock was successfully created. -.Pp -.Dv UU_LOCK_OPEN_ERR : -The lock file could not be opened via -.Xr open 2 . -.Pp -.Dv UU_LOCK_READ_ERR : -The lock file could not be read via -.Xr read 2 . -.Pp -.Dv UU_LOCK_CREAT_ERR : -Can't create temporary lock file via -.Xr creat 3 . -.Pp -.Dv UU_LOCK_WRITE_ERR : -The current process ID could not be written to the lock file via a call to -.Xr write 2 . -.Pp -.Dv UU_LOCK_LINK_ERR : -Can't link temporary lock file via -.Xr link 2 . -.Pp -.Dv UU_LOCK_TRY_ERR : -Locking attempts are failed after 5 tries. -.Pp -If a value of -.Dv UU_LOCK_OK -is passed to -.Fn uu_lockerr , -an empty string is returned. -Otherwise, a string specifying -the reason for failure is returned. -.Fn uu_lockerr -uses the current value of -.Va errno -to determine the exact error. -Care should be made not to allow -.Va errno -to be changed between calls to -.Fn uu_lock -and -.Fn uu_lockerr . -.Pp -.Fn uu_lock_txfr -may return any of the following values: -.Pp -.Dv UU_LOCK_OK : -The transfer was successful. -The specified process now holds the device lock. -.Pp -.Dv UU_LOCK_OWNER_ERR : -The current process does not already own a lock on the specified device. -.Pp -.Dv UU_LOCK_WRITE_ERR : -The new process ID could not be written to the lock file via a call to -.Xr write 2 . -.Sh ERRORS -If -.Fn uu_lock -returns one of the error values above, the global value -.Va errno -can be used to determine the cause. -Refer to the respective manual pages for further details. -.Pp -.Fn uu_unlock -will set the global variable -.Va errno -to reflect the reason that the lock file could not be removed. -Refer to the description of -.Xr unlink 2 -for further details. -.Sh SEE ALSO -.Xr lseek 2 , -.Xr open 2 , -.Xr read 2 , -.Xr write 2 -.Sh BUGS -It is possible that a stale lock is not recognised as such if a new -process is assigned the same process ID as the program that left -the stale lock. -.Pp -The calling process must have write permissions to the -.Pa /var/spool/lock -directory. -There is no mechanism in place to ensure that the -permissions of this directory are the same as those of the -serial devices that might be locked. diff --git a/lib/libutil/uucplock.c b/lib/libutil/uucplock.c @@ -1,225 +0,0 @@ -/* $OpenBSD: uucplock.c,v 1.17 2015/11/11 01:12:09 deraadt Exp $ */ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <paths.h> -#include <string.h> -#include "util.h" - -#define MAXTRIES 5 - -#define LOCKTMP "LCKTMP..%ld" -#define LOCKFMT "LCK..%s" - -#define GORET(level, val) { err = errno; uuerr = (val); \ - goto __CONCAT(ret, level); } - -/* Forward declarations */ -static int put_pid(int fd, pid_t pid); -static pid_t get_pid(int fd,int *err); - -/* - * uucp style locking routines - */ -int -uu_lock(const char *ttyname) -{ - char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], - lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; - int fd, tmpfd, i, err, uuerr; - pid_t pid, pid_old; - - pid = getpid(); - (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, - (long)pid); - (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, - ttyname); - if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY, 0664)) < 0) - GORET(0, UU_LOCK_CREAT_ERR); - - for (i = 0; i < MAXTRIES; i++) { - if (link(lcktmpname, lckname) < 0) { - if (errno != EEXIST) - GORET(1, UU_LOCK_LINK_ERR); - /* - * file is already locked - * check to see if the process holding the lock - * still exists - */ - if ((fd = open(lckname, O_RDONLY)) < 0) - GORET(1, UU_LOCK_OPEN_ERR); - - if ((pid_old = get_pid(fd, &err)) == -1) - GORET(2, UU_LOCK_READ_ERR); - - close(fd); - - if (kill(pid_old, 0) == 0 || errno != ESRCH) - GORET(1, UU_LOCK_INUSE); - /* - * The process that locked the file isn't running, so - * we'll lock it ourselves - */ - (void)unlink(lckname); - } else { - if (!put_pid(tmpfd, pid)) - GORET(3, UU_LOCK_WRITE_ERR); - break; - } - } - GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); - -ret3: - (void)unlink(lckname); - goto ret1; -ret2: - (void)close(fd); -ret1: - (void)close(tmpfd); - (void)unlink(lcktmpname); -ret0: - errno = err; - return uuerr; -} - -int -uu_lock_txfr(const char *ttyname, pid_t pid) -{ - char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; - int fd, err, ret; - - snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname); - - if ((fd = open(lckname, O_RDWR)) < 0) - return UU_LOCK_OWNER_ERR; - if (get_pid(fd, &err) != getpid()) - ret = UU_LOCK_OWNER_ERR; - else { - lseek(fd, 0, SEEK_SET); - ret = put_pid(fd, pid) ? UU_LOCK_OK : UU_LOCK_WRITE_ERR; - } - - close(fd); - return ret; -} - -int -uu_unlock(const char *ttyname) -{ - char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; - - (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); - return unlink(tbuf); -} - -const char * -uu_lockerr(int uu_lockresult) -{ - static char errbuf[128]; - char *fmt; - - switch (uu_lockresult) { - case UU_LOCK_INUSE: - return "device in use"; - case UU_LOCK_OK: - return ""; - case UU_LOCK_OPEN_ERR: - fmt = "open error: %s"; - break; - case UU_LOCK_READ_ERR: - fmt = "read error: %s"; - break; - case UU_LOCK_CREAT_ERR: - fmt = "creat error: %s"; - break; - case UU_LOCK_WRITE_ERR: - fmt = "write error: %s"; - break; - case UU_LOCK_LINK_ERR: - fmt = "link error: %s"; - break; - case UU_LOCK_TRY_ERR: - fmt = "too many tries: %s"; - break; - case UU_LOCK_OWNER_ERR: - fmt = "not locking process: %s"; - break; - default: - fmt = "undefined error: %s"; - break; - } - - (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno)); - return errbuf; -} - -static int -put_pid(int fd, pid_t pid) -{ - char buf[32]; - int len; - - len = snprintf(buf, sizeof buf, "%10ld\n", (long)pid); - - if (len < sizeof buf && len != -1 && write(fd, buf, (size_t)len) == len) { - /* We don't mind too much if ftruncate() fails - see get_pid */ - ftruncate(fd, (off_t)len); - return 1; - } - return 0; -} - -static pid_t -get_pid(int fd, int *err) -{ - ssize_t bytes_read; - char buf[32]; - pid_t pid; - - bytes_read = read(fd, buf, sizeof (buf) - 1); - if (bytes_read > 0) { - buf[bytes_read] = '\0'; - pid = (pid_t)strtoul(buf, (char **) NULL, 10); - } else { - pid = -1; - *err = bytes_read ? errno : EINVAL; - } - return pid; -} diff --git a/mk/bsd.prog.mk b/mk/bsd.prog.mk @@ -11,10 +11,10 @@ LIBPATHS+= ${.TOPDIR}/obj/lib ${.TOPDIR}/lib _find_lib= $(firstword $(wildcard $(LIBPATHS:%=%/$(1)))) LIBC?= $(call _find_lib,libopenbsd/libopenbsd.a) -LIBUTIL?= $(call _find_lib,libutil/libutil.a) +LIBOUTIL?= $(call _find_lib,liboutil/liboutil.a) -ifeq (-lutil,$(filter -lutil,$(LDADD))) -LDFLAGS+= -L$(dir $(LIBUTIL)) +ifeq (-loutil,$(filter -loutil,$(LDADD))) +LDFLAGS+= -L$(dir $(LIBOUTIL)) endif LDFLAGS+= -L$(dir $(LIBC)) $(LDADD) -lopenbsd diff --git a/usr.bin/du/Makefile b/usr.bin/du/Makefile @@ -4,6 +4,6 @@ PROG= du DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD= -loutil include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/usr.bin/file/Makefile b/usr.bin/file/Makefile @@ -7,7 +7,7 @@ SRCS= file.c magic-dump.c magic-load.c magic-test.c magic-common.c \ text.c xmalloc.c MAN= file.1 magic.5 -LDADD= -lutil +LDADD= -loutil DPADD= ${LIBUTIL} CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 diff --git a/usr.bin/sdiff/Makefile b/usr.bin/sdiff/Makefile @@ -6,7 +6,7 @@ PROG=sdiff SRCS=common.c edit.c sdiff.c COPTS+=-Wall -W -LDADD+= -lutil +LDADD+= -loutil DPADD+= ${LIBUTIL} include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/usr.bin/tsort/Makefile b/usr.bin/tsort/Makefile @@ -7,6 +7,6 @@ SRCS = tsort.c CDIAGFLAGS = -Wall -Wno-char-subscripts -Wstrict-prototypes -pedantic -W DPADD += ${LIBUTIL} -LDADD += -lutil +LDADD += -loutil include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/usr.bin/wc/Makefile b/usr.bin/wc/Makefile @@ -4,6 +4,6 @@ PROG= wc DPADD= ${LIBUTIL} -LDADD= -lutil +LDADD= -loutil include ${.TOPDIR}/mk/bsd.prog.mk diff --git a/usr.sbin/rdate/Makefile b/usr.sbin/rdate/Makefile @@ -6,7 +6,7 @@ PROG= rdate SRCS= rdate.c rfc868time.c ntp.c ntpleaps.c CFLAGS+=-Wall DPADD+= ${LIBUTIL} -LDADD+= -lutil +LDADD+= -loutil MAN= rdate.8